`

jvm之String 在jvm中分配

阅读更多
----------~开篇分享一句话:【纸上得来终觉浅,绝知此事要躬行】~---------------------------------------

关于String的些许探讨
首先看下面的案例:
/**
	 * JVM对于字符串常量的"+"号连接,将程序编译期,JVM就将常量字符串的"+"连接优化为连接后的值,拿"a" + 1来说,经编译器优化后在class中就已经是a1。在编译期其字符串常量的值就确定下来,故上面程序最终的结果都为true。
	 */
	@Test
	public void testConstant() {
		if (true) {
			String a = "a1";
			String b = "a" + 1;
			System.out.println((a == b)); // result = true
		}
		if (true) {
			String a = "atrue";
			String b = "a" + "true";
			System.out.println((a == b)); // result = true
		}
		if (true) {
			String a = "a3.4";
			String b = "a" + 3.4;
			System.out.println((a == b)); // result = true
		}
	}

	/**
	 * JVM对于字符串引用,由于在字符串的"+"连接中,有字符串引用存在,而引用的值在程序编译期是无法确定的,即"a" + bb无法被编译器优化,只有在程序运行期来动态分配并将连接后的新地址赋给b。所以上面程序的结果也就为false。
	 */
	@Test
	public void testConstantAB() {
		String a = "ab";
		String bb = "b";
		String b = "a" + bb;
		System.out.println((a == b)); // result = false
	}

	/**
	 * 分析:和上面testConstantAB中唯一不同的是bb字符串加了final修饰,对于final修饰的变量,它在编译时被解析为常量值的一个本地拷贝存储到自己的常量池中或嵌入到它的字节码流中。所以此时的"a" + bb和"a" + "b"效果是一样的。故上面程序的结果为true。
	 */
	@Test
	public void testConstantFinalAB() {
		String a = "ab";
		final String bb = "b";
		String b = "a" + bb;
		System.out.println((a == b)); // result = true
	}

	/**
	 * JVM对于字符串引用bb,它的值在编译期无法确定,只有在程序运行期调用方法后,将方法的返回值和"a"来动态连接并分配地址为b,
	 * 故上面程序的结果为false。
	 */
	@Test
	public void testConstantFinalFunctionAB() {
		String a = "ab";
		final String bb = getBB();
		String b = "a" + bb;
		System.out.println((a == b)); // result = false
	}

	private static String getBB() {
		return "b";
	}



------------------------------------------------------------------------------------------------------------------
分析结论:
------------------------------------------------------------------------------------------------------------------

1、String a = "a1"; 变量a对应的字符串a1 分配在了PSPermGen的常量池。
证明思路:
jvm参数配置:-Xmx200M -Xms200M -Xmn100M -XX:SurvivorRatio=8   -XX:+PrintGCDetails -verbose:gc
java代码:
public static void main(String[] args) {
  System.gc();
}

日志:
PSPermGen       total 21248K, used 3054K [0x00000000ee600000, 0x00000000efac0000, 0x00000000f3800000)
public static void main(String[] args) {
		System.gc();
		String s1= "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa";
		String s4= "baaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa";
		System.gc();

日志:
PSPermGen       total 21248K, used 3057K [0x00000000ee600000, 0x00000000efac0000, 0x00000000f3800000)
证明 PSPermGen区由3054K增长了3K到3057K

2、String a = "ab"; final String bb = "b"; String b = "a" + bb; b同样分配在了常量区
证明思路:
public static void main(String[] args) {
		System.gc();
		final String s1= "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa";
		final String s4= "baaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa";
		String s5 = s1 + s4;
		System.gc();

PSPermGen       total 21248K, used 3060K [0x00000000ee600000, 0x00000000efac0000, 0x00000000f3800000)
证明:PSPermGen区由3057K->3060K,增长的依旧常量池。

3、String a = "ab"; String bb = "b"; String b = "a" + bb; b分配在了堆区。
证明思路:
方法1、调试 b = "a" + bb; 你会发现代码进入了StringBuilder
方法2如下:
public static void main(String[] args) {
  System.gc();
}

日志:
PSYoungGen      total 92160K, used 3276K [0x00000000f9c00000, 0x0000000100000000, 0x0000000100000000)
eden space 81920K, 4% used [0x00000000f9c00000,0x00000000f9f333b0,0x00000000fec00000)
public static void main(String[] args) {
		String s1= "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa";
		String s4= "baaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa";
		long begin = Runtime.getRuntime().freeMemory();
		 for(int i=0;i<300;i++){
			String temp =  s1+"-"+i+"-"+s4;
		 }		 
		long end = Runtime.getRuntime().freeMemory();
		System.out.println((begin - end)/1024 + "KB");
	}	

日志:
PSYoungGen      total 92160K, used 4916K [0x00000000f9c00000, 0x0000000100000000, 0x0000000100000000)
eden space 81920K, 6% used [0x00000000f9c00000,0x00000000fa0cd160,0x00000000fec00000)
对比说明eden 内存量在减少,说明"a" + bb 在jvm的存在是堆的eden区
0
0
分享到:
评论

相关推荐

    JVM系列之String.intern的性能解析

    主要介绍了JVM系列之String.intern的性能解析,本文通过实例代码给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友可以参考下

    论文研究-基于JVM内存模型的String分析 .pdf

    基于JVM内存模型的String分析,王培,程明,本文首先介绍了运行时的Java程序的内存管理模型中的方法区、堆和Java栈等几块内存区域,又介绍了存于堆中的常量池这块比较特殊的内�

    [jvm]深入JVM(一):从

    java解析CONSTANT_String_info时,java虚拟机必须把一个字符串对象的引用,放到constant pool entry 中。每个java虚拟机维护着一张列表,里面有所有程序被"interned"的字符串对象的引用。 查看constPoolOop.cpp文件 ...

    Java进阶教程解密JVM视频教程

    彻底分析 StringTable的相关知识与性能优化,掌握直接内存分配原理和释放手段。 * 在垃圾回收章节,不仅会介绍垃圾回收算法、分代垃圾回收机制,还会重点介绍 G1 垃圾回收器,辨析 Full GC 发生条件,jdk8以来对垃圾...

    StringTable.pdf

    资源描述: 1.JVM中StringTable的所有内容-xmind脑图 2.资源内容:JVM中StringTable的所有内容 3.学习目标:了解jvm底层原理 4.特点:简单易懂,容易上手 5.使用说明:需要使用xmind打开

    JVM内存分配及String常用方法解析

    主要介绍了JVM内存分配及String常用方法解析,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友可以参考下

    最新java面试专题01-JVM

    程序中的public static void main(String[] args)方法作为JVM实例运行的起点。 垃圾收集:JVM具有自动内存管理和垃圾收集机制,用于自动回收不再使用的对象占用的内存空间。垃圾收集器可以根据不同的算法和策略进行...

    深入理解JVM实战篇-String类1

    A2:当一个String实例调 用 intern() 方法时,Java查找常量池中是否有相同Unicode 的字符串常量,如果有,则返回其的引用,如果没有,则在

    java 6 jvm 参数选项大全

    为了让读者明白每个选项的含义,作者在原文基础上补充了大量的资料。希望这份文档,对正在 研究JVM参数的朋友有帮助! 另外,考虑到本文档是初稿,如有描述错误,敬请指正。 非稳态选项使用说明  -XX:+...

    StringTable.xmind

    自己总结的jvm中StringTable的笔记,绘制了详细的思维导图,每个思维导图中均有详细的博文解释,方便大家学习和理解,免费分享给大家。适合jvm的爱好者和学习者

    测试JVM字符串长度的testcase

    用于测试Java字符串长度的testcase,-jar文件,可以通过设置JVM的内存设置 VM argument(eclipse中方便设置)来考察java string可以接受的长度 总体评价来看,java字符串可以任意长,除非字长超出JVM的内存限制,...

    java8rt.jar源码-mini-jvm:Go语言实现的JVM,实现了部分字节码的解释执行,学习JVM使用

    Mini-JVM首先会从classpath中加载主类的class文件,然后找到main方法的字节码解释执行;执行过程中如果遇到新的类符号引用,则会通过全限定性名再从classpath中加载新的类文件,以此类推; 控制台输出、多线程功能...

    Go的JVM实现-Golang开发

    用法Hello world HelloWorld.java公共类HelloWorld {public static void main(String [] args){System.out.println(“ H​​ello world”); $ cat HelloWorld.class | 去运行main.go(git)-[master](p9)Hello...

    java8源码-jvm-study:jvm-study

    java8 源码 jvm-study 方法执行过程 jvm申请内存 初始化运行时数据区 方法区:存放 class;静态变量:常量 堆:实例对象 栈:栈帧(对象的引用,方法) ...可以看jvm参数查看网址 ...字面量(String a =

    node-jvm:纯node.js中的Java虚拟机

    node-jvm-纯node.js中的jvm 例 Java public class Main { public static long fib ( int n ) { if (n &lt;= 1 ) return n; return fib(n - 1 ) + fib(n - 2 ); } public static void main ( String [] args )...

    java io读取文件到String

    public static String loadAFileToStringDE1(File f) throws IOException { ...只有方法3 可以通过,设置到-Xmx256M时也只有方法3可以通过,干脆设置512M,都可以了,运行时间如果正常的话一般都在4~5S

    harmonyos2-kotlin-format:Kotlin中JavaString.format()的替代品(JVM、Native、JS)

    中 Java String.format() 的替代品(JVM、Native、JS) 目前没有 String.format() 的原生 Kotlin 模拟。 在 JVM 上,Kotlin 标准库依赖于 Java 实现,因此在为 Native 或 JS 目标构建时不能使用它。 该代码是通过...

    字符数组的存储方式 字符串常量池.docx

    为了避免每次都创建相同的字符串对象及内存分配,JVM内部对字符串对象的创建做了一定的优化,在Permanent Generation中专门有一块区域用来存储字符串常量池(一组指针指向Heap中的String对象的内存地址)。...

    JVM应用监控框架Kamon.zip

    Kamon 是一组用于监控运行在 JVM 上的应用的工具和框架。示例代码:public class GetStarted {  public static void main(String[] args) {  Kamon.start();  final Histogram someHistogram = ...

Global site tag (gtag.js) - Google Analytics