深入理解java虚拟机——java内存区域

来源:互联网 发布:新一代人工智能发展 编辑:程序博客网 时间:2024/05/22 11:19
常识:
JIT  实时生产系统(just in time)


运行时的数据区


1.线程隔离的数据区
①程序计数器, 如果执行的是Native方法的时候,这个计数器的值为空
②虚拟机栈, 每个方法在执行的同时都会创建一个栈帧, 用来存储局部变量表,操作数栈,动态链接,方法出口等信息
③本地方法栈, 与虚拟机栈的作用相似,但是该栈是为Native方法服务的

2.由所有线程共享的数据区
①java堆,java虚拟机中管理的内存中最大的一块, 几乎所有的对象实例都在这里分配内存,该区域是垃圾回收的主要区域, java堆还可以细分为:新生代和老年代;再细致一点的话可以分为Eden空间,From survivor空间, To survivor空间
②方法区,用于存储已被虚拟机加载的类信息,常量,静态变量,即使编译器编译后的代码等数据, 别名为non-heap, 很多人更加愿意称其为"永久代", 常量池是在这个区域的




对象的创建
①虚拟机要对对象进行必要的设置, eg:这个对象时哪个类的对象,如何才能找到类的元数据信息,对象的哈希码,对象的gc分代年龄等信息。这些信息存放在对象的对象头之中
对象的内存布局


②对象在内存中存储的布局可以分为3块区域:对象头, 实例数据和对齐填充
1) 对象头:其中中包含两部分的数据 一部分用于存储对象自身的运行时的数据(大小根据虚拟机的位数来进行确定) 另外一部分是类型指针  即对象指向它的类元数据的指针,另外如果对象是一个java数组,那在对象头中还必须有一块用于记录数组长度的数据
2) 实例数据:对象真正存储的有效信息
3)填充部分并不是一定存在的, 对象的大小必须是8字节的整数倍


对象的访问( 分为对象实例数据, 对象类型数据)
①引用直接指向句柄池, 然后句柄池中的指针指向别处的对象地址  如果对象的地址发生改变,只会改变句柄的指向即可
②直接指针访问  java栈本地变量表中存储的就是一个地址了    访问的速度比较快(Hotspot使用的是该种方式)


java堆溢出
如果产生了堆溢出的话,可以使用内存映像分析工具进行分析
如果是内存泄露的话, 可以进一步通过工具查看泄露对象到GC root的引用链, 如果找不到的话则应该去查看虚拟机的堆参数


Hotspot中不区分虚拟机栈和本地方法栈  
如果线程请求的栈深度大于虚拟机所允许的最大深度   则将抛出StackOutflowError错误
如果虚拟机在扩展栈是无法申请到足够的内存空间时, 则抛出OutOfMemoryError异常


虚拟机提供了参数来限制java堆和方法区这两部分内存的最大值
应为程序计数器使用的内存空间很少, 几乎可以忽略不计, 则内存除了这两部分其余剩下的空间用来存放本地方法栈和虚拟机栈


tip:String.intern(), 此方法表示, 如果常量池中存在该字符串的话, 则返回代表池中这个字符串的String对象, 如果不存在的话, 则将这个字符串加到常量池中,返回的是此String对象的引用
1.6和1.7中String.intern()方法的区别
jdk1.6中如果字符串是首次出现, 则会将字符串复制到永久区, 然后返回相应的引用, 如果是jdk1.7的话, 则只是在常量池中记录首次出现实例的引用
如果经常动态生成大量的Class的应用中, 需要特别注意类的回收状况




本机直接内存
如果该内存不通过参数进行限制的话, 默认和heap的最大内存一样大







0 0
原创粉丝点击