《深入理解Java虚拟机》:Java内存区域( 二 )

4、Java堆:Java堆是虚拟机管理内存中最大的一块 , 是被所有线程共享的一块内存区域 , 常说的线程安全 , 指的就是堆中对象的线程安全问题 。 几乎所有new出来的对象都存放在这里 , 常说的内存分配和垃圾回收 , 针对的就是堆内存 。 堆内存按两部分划分 , 可以是新生代和老年代 , 比例1:2;更细粒度划分 , 新生代又分Eden(伊甸园区) , from , to , 比例8:1:1.
1、创建一个MyHeap , 这个对象有一个私有变量byte1 , 占1M内存
public class MyHeap{ private static final int MB = 1024 * 1024;byte[] byte1 = new byte[MB]; public static void main(String[] args) {List list = new ArrayList<>();MyHeap myStack = new MyHeap();list.add(myStack); }}2、配置堆内存初始值和最大值为20M , 其中新生代占10M , 并且打印堆内存信息
-verbose:gc -Xms20M -Xmx20M -Xmn10M -XX:+PrintGCDetails -XX:SurvivorRatio=83、分析运行结果:
可以看出新生代PSYoungGen显示的内存总大小是9216K , 为什么不是设置的10M呢?是因为from和to区总有一个是空闲的 , 不能用来存储对象的(因为垃圾回收需要复制 , 即从from复制到to , to必须和from空间一样大并且空闲 , 才能接收from的对象) 。 MyHeap对象占用了Eden2026K内存 , 2026K/8192K=24%;
老年代ParOldGen有堆内存-新生代:20M-10M=10240K;
永久代PSPermGen有20M 。
Heap PSYoungGentotal 9216K, used 2026K [0x00000000ff600000, 0x0000000100000000, 0x0000000100000000)eden space 8192K, 24% used [0x00000000ff600000,0x00000000ff7faa88,0x00000000ffe00000)from space 1024K, 0% used [0x00000000fff00000,0x00000000fff00000,0x0000000100000000)tospace 1024K, 0% used [0x00000000ffe00000,0x00000000ffe00000,0x00000000fff00000) ParOldGentotal 10240K, used 0K [0x00000000fec00000, 0x00000000ff600000, 0x00000000ff600000)object space 10240K, 0% used [0x00000000fec00000,0x00000000fec00000,0x00000000ff600000) PSPermGentotal 21504K, used 2550K [0x00000000f9a00000, 0x00000000faf00000, 0x00000000fec00000)object space 21504K, 11% used [0x00000000f9a00000,0x00000000f9c7d9f0,0x00000000faf00000)5、方法区:与Java堆一样 , 是线程共享区域 , 主要存储类信息、常量、静态变量、即时编译器编译后的代码等数据 。 hotspot虚拟机实现中把此方法区又称作“永久代” 。 运行时常量区:它是方法区的一部分 。 前面程序计数器字节码文件举例时 , 文件中Constant pool指的就是常量区 , 用于存放编译器生成的各种字面量和符号引用 。
能进入常量池的内容不一定是编译器产生的 , 像String.intern();是在运行时把数据放入常量池的 。
public static void main(String[] args) {String s1 = "a";//行号6String s2 = "b";//行号7String s3 = "ab";//行号8String s4 = s1+s2;//行号9System.out.println("ab"==s4);//行号10}//行号11以上代码编译后的部分字节码如下 , 我们发现第9行代码编译成了new StringBuilder对象 , 而6,7,8行代码编译后分别是0,3,6对应的常量字符串 , 所以可以验证第11行输出肯定是false , 因为s4对象在堆中 , 而s3在常量池 。
public static void main(java.lang.String[]);flags: ACC_PUBLIC, ACC_STATICCode:stack=3, locals=5, args_size=10: ldc#16// String a2: astore_13: ldc#18// String b5: astore_26: ldc#20// String ab8: astore_39: new#22// class java/lang/StringBuilder12: dup13: aload_114: invokestatic#24// Method java/lang/String.valueOf:(Ljava/lang/Object;)Ljava/lang/String;17: invokespecial #30// Method java/lang/StringBuilder."


推荐阅读