笔记,深入理解java虚拟机

Java运行时内存区域

程序计数器,线程独占,当前线程所执行的字节码的行号指示器,每个线程需要记录下执行到哪儿了,下次调度的时候可以继续执行,这个区是唯一不会发生oom的

,线程独占,包含虚拟机栈或native method stack,用于存放局部变量的

,线程共享,用于分布对象实例的,后面说的内存管理和垃圾回收基本都是针对堆的

方法区,线程共享,用于存放被虚拟机加载的类,常量,静态变量; Java虚拟机规范,把方法区描述为堆的逻辑部分,所以也被称为“永久代”,在大量使用反射,动态代理,ClassLoader的场景下,要考虑永久代的回收

对于一个简单的,对象生成

Object obj = new Object();

会涉及到3个区,

图中描述两种对象访问方式,有句柄,可以屏蔽对象实际地址的改变(gc时对象地址经常会改变),不用句柄效率更高

垃圾回收

垃圾判定

对于如何判定对象是垃圾,教科书的答案是引用计数,并且也在COM,python中得到较好的应用

引用计数的问题是,难以解决循环引用的问题,
A.instance = B; B.instance =A
这样会导致A,B的引用计数都不为0

所以对于Java,C#,Lisp都是采用GC Roots Tracing的方式,
原理也很简单,就是选取一系列GC Roots对象,只保留从root对象可达的对象,其余都是垃圾

Java中的GC roots包含,

  • JavaStack中的引用的对象
  • 方法区中静态引用指向的对象
  • 方法区中常量引用指向的对象
  • Native方法中JNI引用的对象

垃圾回收算法

Mark-Sweep,最原始的想法,先标记出所有垃圾对象,然后回收掉;问题是,效率低,而且会产生大量内存碎片

Copying,最简单的copying,把内存分两半,先用一半,然后回收时,把有效对象copy到另外一半

这个首先只适用于年轻代,即垃圾对象占较高比例的case
再者,空间太浪费了,只能用一半

所以,现在实际使用的版本为,分为一个较大的eden区,两个较小的survivor区
比例一般为8:1:1,其中一个survivor区是空的,这样只浪费10%的空间
能这样做的前提就是,每次只有最多10%的对象存活
对象先放到eden区,eden区满了,进行minor gc,把eden区和有数据的survivor区的存活对象,放到另一个空的survivor区中
两个survivor区,虽然命名为from和to,但是其实没有任何区别,完全对等的

当如果survivor区的空间不够,就需要放到年老代(称为handle promotion,即年老代要为survivor提供担保,你那空间不够,可以放我这,类似贷款担保),如果年老代的空间也不够或不能接受Handle promotion失败,就需要full gc去回收年老代

Mark-Compact,前面说copying只适用于存活对象比例较低的case,所以适合年轻代,但对于年老代这样的,用copying肯定是不行的;
Mark-compact,mark还是一样的,只是在回收时,会把对象做平移,消除碎片

垃圾收集器

Serial收集器

最简单的,单线程,收集时会stop the world,所有用户线程暂停
可以用于收集新生代或老年代
收集新生代,用copying算法
收集老年代,用标记-整理,称为serial old

简单高效,适用于单CPU环境;是虚拟机Client模式的默认收集器
缺点,会stop the world

ParNew收集器

只是serial的多线程版本,适用于多核环境,如果在单核的机器上,效率还不如serial
优势是,可以配合CMS收集器使用,因为CMS作为老年代的收集器,只能配合Serial或ParNew作为新生代的收集器

CMS(Concurrent Mark Sweep)收集器

以最短停顿时间为目标的收集器,适合用于网站或B/S系统的服务端,重视服务响应速度的场景。
该收集器相对比较复杂,整个过程分为,
1. 初始标记(CMS initial mark),stop the world,标记GC Roots直接关联到的对象,速度很快
2. 并发标记(CMS concurrenr mark), 并行进行GC Roots Tracing的过程
3. 重新标记(CMS remark),stop the world,由于并发标记和用户线程是并发执行的,所以需要对标记进行最后的修正,消耗时间会大大小于并发标记时间
4. 并发清除(CMS concurrent sweep),最后进行sweep

缺点,
a. CPU敏感,频繁GC会导致CPU卡死
b. 无法处理浮动垃圾(floating garbage),在并发清理阶段产生的新垃圾无法在这次完成回收
c. 需要预留较大的内存,由于CMS收集过程是和用户应用并发进行的,所以不能等到老年代快被占满再做,需要提前进行收集,默认是设为68%,这是比较保守的设定,可以减少以降低gc的次数;但是如果在CMS收集过程中,出现用户应用程序内存不够的情况,会发生”Concurrent Mode Failure”,这样虚拟机只能用后备方案,serial old收集器进行年老代的收集(因为应用已经无法并发执行),这样应用停顿时间就会很长,所以需要设置合理的比例
d. 因为采用sweep,会有大量碎片

Parallel Scavenge收集器

新生代收集器,设计目的是达到可控制的throughput,CPU运行用户代码时间/CPU总消耗时间,说白了,就是保证CPU更多的执行用户代码而非gc
适合后台运算,不太需要交互的场景

但鱼和熊掌不可兼得,throughput和GC停顿时间是需要tradeoff的
降低新生代的空间大小,缩小gc的间隔,都可以减少GC的停顿时间,但也会降低throughput

并且该收集器,支持UseAdaptiveSizePolicy参数, 这样不需要使用者指定新生代大小,Eden和Survivor比例,年老代晋升年龄等,虚拟机会根据运行性能监控去优化调整

Parallel Old收集器

前面提到的parallel sacvenge收集器是无法与CMS收集器配合使用的,所以之前只能配合Serial Old来收集老年代,导致效率低
Parallel Old作为Serial Old的多线程版本,可以更好的和parallel sacvenge收集器配合,真正达到throughput优先的收集

G1(Garbage First)收集器

新一代的收集器,不同于之前的收集器,会收集整个新生代或老年代
G1会把整个Java堆划分为多个固定大小的区域,并跟踪垃圾堆积程度,并每次收集垃圾最多的区域,可以大大提高收集效率

JVM收集器对应参数

内存分配和回收策略

对象往往在新生代的Eden区分配,Eden区空间不够,发起minor gc,会将eden和一个survivor区的存活对象copy到另一个survivor区,如果另一个survivor区空间不够,存入老年代

大对象会直接进入老年代,比如很长的字符串或很大的数组,大对象对于JVM内存分配是个坏消息,因为大对象需要找到连续内存,否则会触发gc,所以短命的大对象是需要尽量避免的

长期存活的对象进入老年代,对象在新生代每经历一次minor gc,年龄加1, 默认达到15岁会进入老年代

每次Minor GC时,虚拟机会检测每次晋升到老年代的平均大小是否大于老年代当前剩余大小,如果小于,则进行full gc

Java内存管理和垃圾回收的更多相关文章

  1. Java内存管理及垃圾回收总结

    概述 Java和C++的一个很重要的差别在于对内存的管理.Java的自己主动内存管理及垃圾回收技术使得Java程序猿不须要释放废弃对象的内存.从而简化了编程的过程.同一时候也避免了因程序猿的疏漏而导致 ...

  2. java基础(一):谈谈java内存管理与垃圾回收机制

    看了很多java内存管理的文章或者博客,写的要么笼统,要么划分的不正确,且很多文章都千篇一律.例如部分地方将jvm笼统的分为堆.栈.程序计数器,这么分太过于笼统,无法清晰的阐述java的内存管理模型: ...

  3. Java内存管理 -JVM 垃圾回收

    版权声明:本文为博主原创文章,未经博主允许不得转载 一.概述 相比起C和C++的自己回收内存,JAVA要方便得多,因为JVM会为我们自动分配内存以及回收内存. 在之前的JVM 之内存管理 中,我们介绍 ...

  4. Java基础--Java内存管理与垃圾回收

      Java自动内存管理 在讲解内存管理之前,首先需要了解对象和对象引用的区别 对象是类的一个实例,以人这个类为例,Person是我们定义的一个类 public class Person{} publ ...

  5. java内存管理之垃圾回收及JVM调优

    GC(garbage Collector 垃圾收集器)作用:a.内存的动态分配:b.垃圾回收注:Java所承诺的自动内存管理主要是针对对象内存的回收和对象内存的分配. 一.垃圾标记 程序计数器.Jav ...

  6. Java之美[从菜鸟到高手演变]之JVM内存管理及垃圾回收

    很多Java面试的时候,都会问到有关Java垃圾回收的问题,提到垃圾回收肯定要涉及到JVM内存管理机制,Java语言的执行效率一直被C.C++程序员所嘲笑,其实,事实就是这样,Java在执行效率方面确 ...

  7. JVM原理(Java代码编译和执行的整个过程+JVM内存管理及垃圾回收机制)

    转载注明出处: http://blog.csdn.net/cutesource/article/details/5904501 JVM工作原理和特点主要是指操作系统装入JVM是通过jdk中Java.e ...

  8. java Vamei快速教程22 内存管理和垃圾回收

    作者:Vamei 出处:http://www.cnblogs.com/vamei 欢迎转载,也请保留这段声明.谢谢! 整个教程中已经不时的出现一些内存管理和垃圾回收的相关知识.这里进行一个小小的总结. ...

  9. JVM内存管理及垃圾回收【转】

    很多Java面试的时候,都会问到有关Java垃圾回收的问题,提到垃圾回收肯定要涉及到JVM内存管理机制,Java语言的执行效率一直被C.C++程序员所嘲笑,其实,事实就是这样,Java在执行效率方面确 ...

随机推荐

  1. x264_param_t结构体参数分析

    转自:http://blog.chinaunix.net/uid-17053077-id-1987955.html 参考网上的一些资料,结合个人的理解,对x264中x264_param_t结构体作了初 ...

  2. TabLayout

    效果图: 标题和fragment联动效果已经封装好了,非常方便 <android.support.design.widget.TabLayout android:id="@+id/ta ...

  3. Arduino可穿戴开发入门教程(大学霸内部资料)

    Arduino可穿戴开发入门教程(大学霸内部资料) 试读下载地址:链接:http://pan.baidu.com/s/1mg9To28 密码:z5v8 介绍:Arduino可穿戴开发入门教程(大学霸内 ...

  4. Google地图接口API之地图控件集(五)

    1.默认控件集 当使用一个标准的google地图,它的控件默认设置如下: (1). Zoom-显示一个滑动条来控制map的Zoom级别,如下所示:

  5. 博客搬到blog.csgrandeur.com

    博客已搬到blog.csgrandeur.com. cnblogs停止更新. wordpress太臃肿,难刷. hexo对windows似乎不太友好,迁移的时候建了十几层文件夹,导致目录过深无法移动无 ...

  6. 生成跨语言的类型声明和接口绑定的工具(Djinni )

    Djinni 是一个用来生成跨语言的类型声明和接口绑定的工具,主要用于 C++ 和 Java 以及 Objective-C 间的互通. 示例接口定义文件: # Multi-line comments ...

  7. CentOS6.4 配置mysql服务器启动多个端口,同步单表数据

    ============================================================ ====多端口启动==== ========================= ...

  8. COJ1013 : WZJ的数据结构(十三)

    这道题有这样一个解法: 首先把边依次加到图中,若当前这条边与图中的边形成了环,那么把这个环中最早加进来的边弹出去并将每条边把哪条边弹了出去记录下来:ntr[i] = j,特别地,要是没有弹出边,ntr ...

  9. NOIP200406合并果子

    试题描述 在一个果园里,多多已经将所有的果子打了下来,而且按果子的不同种类分成了不同的堆.多多决定把所有的果子合成一堆.    每一次合并,多多可以把两堆果子合并到一起,消耗的体力等于两堆果子的重量之 ...

  10. jquery easyui datagrid 分页详解

    由于项目原因,用了jquery easyui 感觉界面不错,皮肤样式少点,可是官网最近打不开了,资料比较少,给的demo没有想要的效果,今天在用datagrid 做分页显示的时候,折腾了半天,网上的资 ...