解密JVM内存管理

来源:互联网 发布:ubuntu win7双系统 编辑:程序博客网 时间:2024/05/16 06:40

内存分区

线程共享方法区

线程私有内存虚拟机栈(栈)、本地方法栈、程序计数器

 

程序计数器因为对于每个线程都会有一个内核来执行因此需要单独的计数器来指向下一条语句位置所以是线程独享

 

虚拟机栈描述java方法的执行的内存模型每个方法执行时会创建一个栈针存储局部变量表操作数表动态链接方法出口

 

局部变量表(编译期可知):存放基本数据类型、引用类型(引用地址)、returnAddress(返回地址),均占1个局部空间,longdouble占两个局部空间(是局部空间),进入方法的时候,需要栈针空间完全确定,不会改变

 

本地方法栈执行本地代码、native方法服务

 

Java所有对象实例数组分配地址但是栈上分配标量替换会导致出现不同解决也被称作GC

 

方法区线程共享用于存储已被虚拟机加载的类信息常量静态变量即时编译器编译后的代码等数据Non-Heap,较少出现垃圾清理行为

 

运行时常量池将类预先置入Class文件中的常量池装载,但是不一定会只有这些,String方法的intern(),这个方法如果池已经包含与equals(Object)方法确定的相当于此String对象的字符串,则返回来自池的字符串。 否则,此String对象将添加到池中,并返回对此String对象的引用。也就是说这个方法可能会产生新的常量,也就是运行时才能知道的常量,也会放到这个常量池

 

 

创建对象

遇到new语句先检查能否在常量池定位到这个类的符号引用然后检查对应的类是否被加载若没加载必须经过加载连接初始化过程,然后分配内存。

 

分配内存两种方式

① 若内存堆规整(一边是使用过的内存,另一边是没使用过的内存),“指针碰撞模式”,每次分配内存只需要将指示边缘的指针向空闲内存方向移动分配大小的距离

② 不规整采用空闲列表记录所有空闲内存块分配后更新空闲列表一般若GC收集器没有Compact过程的采用这种,标记——清理算法

 

并发分配内存情况A分配内存没来得及修改指针导致B再次分配

解决方案

TLAB 将内存分配的动作按照线程来划分不同的空间,不同线程分配在各自的TLAB区域,直到TLAB区域的内存用尽,才会用共用内存,这时候加入同步锁定

 

或者采用CAS配上失败重试的方式保证更新的原子性(同步锁定)

 

 

分配内存后将空间全部初始化为0(不一定在这个时候,如果使用TLAB可能在分配TLAB时就初始化为0),保证实例字段不赋初始值也能使用——基本类型的初始值

 

设置元信息哈希码GC分代年龄(判断进入老年代标志) 占据1~2个字节

 

访问定位通过句柄或直接指向堆对象

通过句柄,GC后的修改方便Sun HotSpot使用-

指向堆对象访问速度快

 

 

通过减少内存来解决内存溢出

 

为线程的栈分配的内存越大那么可建立的线程越少因为总栈内存是固定的因此如果多线程下出现内存溢出问题很有可能是 线程栈的内存过大

 

而栈溢出就不一样

 


原创粉丝点击