笔记,深入理解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. 电赛总结(三)——DA芯片总结

    一.AD7890 1.特性参数 (1)高速12位DA,转换速度5.9us (2)具有8个通道. (3)串行通信 2.芯片管脚图 3.管脚功能 管脚名称 功能 AGND 模拟地 SMODE 控制端,&q ...

  2. SU suamp命令学习

  3. D FFF团的怒火

    Time Limit:1000MS  Memory Limit:65535K 题型: 编程题   语言: 无限制 描述 在信软学院,男女比例失衡已经是习以为常的事情. 在这样的一个学院,诞生了一个神秘 ...

  4. SVN标准命令

    SVN标准命令 范例 checkout 检出 svn  co  URL 检出app/search/news/apache/主干上最新版本到本地工作副本,可执行命令: svn co  https://s ...

  5. HDU 4405 期望DP

    期望DP算是第一题吧...虽然巨水但把思路理理清楚总是好的.. 题意:在一个1×n的格子上掷色子,从0点出发,掷了多少前进几步,同时有些格点直接相连,即若a,b相连,当落到a点时直接飞向b点.求走到n ...

  6. TYVJ P1031 热浪 Label:dijkstra 最短路

    背景 USACO OCT09 9TH 描述 德克萨斯纯朴的民眾们这个夏天正在遭受巨大的热浪!!!他们的德克萨斯长角牛吃起来不错,可是他们并不是很擅长生產富含奶油的乳製品.Farmer John此时以先 ...

  7. 【Vijos】1218 数字游戏

    题目链接:https://vijos.org/p/1218 算法:环形DP+划分型DP 环形DP的思路很简单,将1~n中每一个节点当成起点进行划分型DP即可,关于划分型DP前面论文有介绍~查找tag把 ...

  8. 李洪强-C语言5-函数

    C语言函数 一.函数 C语言程序是由函数构成的,每个函数负责完成一部分的功能,函数将工恩呢该封装起来,以供程序调用. 二.函数定义 目的:将一些常用的功能封装起来,以供日后调用. 步骤:确定函数名,确 ...

  9. php+mysql分页优化版

    <?php include('conn/conn2.php'); $pagesize=5; $url=$_SERVER["REQUEST_URI"];//取当前url路径 $ ...

  10. 以下是关于Controller的一些Hint

    在经过路由分发之后,实际的应用Controller接管用户的所有请求,并负责与用户数据的交互.CI中所有的应用控制器都应该是CI_Controller的子类(除非你扩展了CI的核心,那么你的Contr ...