聊聊jvm之自动内存管理机制

本篇文章主要介绍一下jvm的内存管理机制,包括内存区域和垃圾收集相关内容。

1、jvm运行时数据区域包括方法区(Method Area)、堆(Heap)、虚拟机栈(VM Stack)、本地方法栈(Native Method Stack)和程序计数器(Program Counter Register)。

①程序计数器,可理解为当前线程所执行的字节码的行号指示器,每一个线程都会有一个独立的程序计数器,线程之间独立存储、互不影响。

②虚拟机栈,每个方法在执行的同时都会创建一个栈帧用户存储局部变量表、操作数栈、动态链接、方法出口等信息,每个方法的调用到完成对应着虚拟机栈中入栈到出栈的过程。局部变量表存放各种基本数据类型、对象引用和returnAddree类型(指向一条字节码指令的地址)。若线程请求栈深超过虚拟机允许的深度,会抛出StackOverflowError;虚拟机扩展时无法申请足够内存,会抛出OutOfMemoryError。

③本地方法栈,类似于虚拟机栈,虚拟机栈为java方法服务,而本地方法栈为native方法服务。(Sun HotSpot直接将本地方法栈和虚拟机栈合二为一)

④Java堆,是虚拟机内存管理中最大的一块,所有线程共享,存放对象实例。Java堆是垃圾收集器管理的主要区域,又称“GC堆”(Garbage Collected Heap)。从垃圾回收的角度,可以划分为老年代和新生代,再细致又可划分Eden空间、From Survivor空间,To Survivor空间,从内存分配又可划分多个线程私有的分配缓冲区(Thread Local Allocation Buffer),但存储的还都是对象实例。

⑤方法区,线程共享,存储类信息、常亮、静态变量、即时编译器编译后的代码等数据。HotSpot之前实现上又称方法区为“永久代”,其实更容易出现内存溢出问题(对此区域完全不收集),或逐步改为Native Memory实现,并且将字符串常量池移出(Java技术——你真的了解String类的intern()方法吗,jdk1.7+移到Java Heap)。此外趁机补充一下内存泄漏和内存溢出,内存泄漏:应用使用资源之后没有及时释放资源,导致应用内存中持有的了不需要的资源;内存溢出:应用内存已经不能满足正常的使用,堆栈已经达到系统设置的最大值,导致崩溃。

⑥运行时常量池,用户存放编译期各种字面量和符号引用,运行期间也可将常量放入池中,例如String类的intern()方法。

⑦直接内存(Direct Memory),并不是虚拟机运行时数据区的一部分,也不是java虚拟机规范中定义的内存区域。jdk1.4引入NIO,基于通道(Channel)与缓冲区(buffer)的I/O方式,通过Native库函数直接分配堆外内存,通过Java堆中的DirectByteBuffer对象作为引用进行操作,避免java堆和Native堆来回复制数据,提高性能。

2、对象的创建。

①遇到new指令,在常量池中寻找类的符号引用,检查是否被加载、解析和初始化过,否则进行加载②为新对象分配内存空间③初始化0值(不包括对象头),保证对象不赋初始值可直接使用④设置对象头(Object Header),例如类的元数据、哈希码、分代年龄、是否启用偏向锁等⑤执行init()方法

步骤二为对象分配内存空间有两种方式:“指针碰撞”和“空闲列表”,依据内存规整性做分配,使用Serial(串行收集器)、ParNew(Serial多线程版本)等带有compact(聚集)过程的收集器,系统采用指针碰撞(一边存放对象,一边空闲,每新增一个对象,指针向空闲区域挪动);而使用CMS(Concurrent Mark Sweep 并发标记清理)基于Mark-Sweep算法收集器,通常采用空闲列表法(在分配的时候从列表中找到一块足够大的空间划分给对象)。在并发过程中,虚拟机分配内存有两种策略,对分配内存空间动作进行同步处理,CAS+失败重试;把内存分配动作按线程划分在不同空间进行操作,即本地线程分配缓冲(Thread Local Allocation Buffer, TLAB),通过-XX:+/-UseTLAB设置。

3、对象的内存布局

在HotSopt虚拟机中,对象在内存中的存储布局可分为对象头、实例数据和对齐填充。对象头包含两部分内容①对象自身运行时数据,如哈希码、GC分代年龄、锁状态标准、线程持有的锁、偏向线程ID、偏向时间戳,此部分数据又称“Mark Word”,另一部分,存放类型指针,即类元数据指针,用于判断对象属于哪个类的实例。 实例数据,即各种字段内容、继承信息,默认分配策略是相同宽度的字段分配到一起。对齐填充,对象起始地址必须是8字节的整数倍。

4、对象访问定位

使用对象,即通过栈上的reference数据类操作堆上的具体对象,目前reference存储句柄(handle)地址或直接指针。句柄方式,堆中会分出一块内存作为句柄池,reference存放句柄地址,当对象移动是改变句柄中实例数据的指针,reference本身不必修改;直接指针方式,访问更快,避免一次指针定位时间开销,需要修改reference,HotSpot使用直接指针方式。

5、判断对象“存活”的办法

①引用计数算法:给对象添加一个引用计数器,有一个地方就+1,引用失效就-1,任何时刻,计数为0的对象不可再被引用。jvm没有选用该种算法,该种算法不能解决循环引用问题。

②可达性分析算法:通过一系列“GC Roots”对象作为起始点,从节点向下搜索的路径成为引用链(Reference Chain),当一个对象到GC Roots没有任务引用链,证明不可用。能够作为GC Roots的对象有:虚拟机栈(本地变量表)中引用的对象、方法区中类静态属性应用的变量、方法区中常量引用的对象、本地方法栈JNI(一般是Native)引用的对象。

③引用:当一个对象处于“食之无味弃之可惜”时,以上两种方法就无法判断。在jdk1.2之后,将引用分为强引用(Strong Reference)、软引用(Soft Reference)、弱引用(Weak Reference)、虚引用(Phantom Reference)

强引用:在虚拟机中普遍存在,类似于Object obj = new Object(),只要强引用在,就不会被回收。

软引用:描述有用但并非必需的对象。提供SoftReference类来实现。系统在发生内存溢出之前,会把对象列进回收范围中进行第二次回收,如果回收后还没有足够内存,则抛出内存溢出异常。

弱引用:描述非必需对象,比软引用更弱。提供WeakReference类实现。只能生存到下一次垃圾收集发生之前。收集器工作一定会回收弱引用对象。

虚引用:又称幽灵引用或幻影引用,无法通过虚引用来取得实例。提供PhantomReference。使用虚引用的目的就是在该对象被收集器回收收到一个通知

④java finalize()方法,当对象没有覆盖finalize()方法或finalize()已经被调用,则视为“没有必要执行”,避免通过finalize方法拯救对象。

6、回收方法区,主要回收废弃常量和无用的类。系统没有其他对象引用常量,就会将该常量清理出去。无用的类需要满足:①所有的实例已经被回收②加载该类的ClassLoader已经被回收③该类的Class对象没有被引用,无法在任何地方通过反射访问该类。满足以上条件,可进行回收(应用在大量使用反射、动态代理、CGLib,动态生成JSP、OSGi等功能)。

7、垃圾收集算法

①标记-清除算法(Mark-Sweep),标记和清除两个过程效率不高,容易产生内存碎片。

②复制算法,将内存分两半,每次只用其中一半,gc时,将存活的移到另一半,对之前进行清理。代价太高,内存缩小一半。IBM专门研究,将内存(新生代)分配成8:1:1即Eden,form survivor,to survivor,每次只用Eden和一个survivor,清理时将存活的对象移到另一个survivor,空间不足,则依赖老年代内存。

③标记-整理算法(Mark-Compact),跟据老年代特点设计,跟标记-清除类似,不过标记之后,将存活对象往一端移动,清除端边界以外的内存。

④分代收集(Generational Collection),根据对象存活周期不同,划分为几块,选择合适的收集算法。

参考:

《深入理解Java虚拟机》

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 217,826评论 6 506
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 92,968评论 3 395
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 164,234评论 0 354
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 58,562评论 1 293
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 67,611评论 6 392
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 51,482评论 1 302
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 40,271评论 3 418
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 39,166评论 0 276
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 45,608评论 1 314
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,814评论 3 336
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,926评论 1 348
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,644评论 5 346
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 41,249评论 3 329
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,866评论 0 22
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,991评论 1 269
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 48,063评论 3 370
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,871评论 2 354

推荐阅读更多精彩内容