最近看了周志明版本的《深入理解Java虚拟机》第一版和第二版,写的很好,收获很多,此处总结一下。
jvm中内存划分:
如上图,一共分为五块,其中:
线程共享区域为:
1、java堆
2、方法区
线程私有区域为:
3、JVM栈
4、本地方法栈
5、程序计数器
各区域作用:
1、java堆:
java堆是jvm内存管理中最大的一块,线程共享。在jvm启动的时候创建。此区域唯一目的就是存放对象实例,几乎所有的对象实例都在这里分配内存。但是随着JIT编译器(即时编译器)的发展与逃逸分析技术的逐渐成熟,栈上分配、标量替换优化技术将会导致一些微妙变化(对象可能会分配到栈上),所以这种所有对象都分配在堆上也不是那么绝对的。
java堆细分为新生代和老年代,新生代又分为Eden空间、From Survivor空间、To Survivor空间,新生代中垃圾回收算法为复制算法,复制算法是先将内存分为连个部分,一部分用来放入对象,而另一部分暂时不用,当使用的一部分内存要进行垃圾回收的时候会将不需要回收的对象复制保存在另一个空间中,然后再对使用过的那部分区域进行垃圾回收,这样虽然效率很高,但是很浪费空间,所以一般将新生代分为Eden空间和两个Survivor空间,其大小在HotSpot虚拟机中默认比例为8:1:1,这样在新生代中采用复制算法回收垃圾效率就很高了,具体回收过程是将Eden区域和From Survivor区域作为对象的存储空间,当要进行垃圾回收的时候先将这两个区域中不需要回收的对象复制保存在To Survivor区域中,然后再进行垃圾回收。另外有一点是当一个对象在Eden区域和From Survivor区域中存储的时候发现内存不足,这时会进行内存分配担保,就是将此对象直接存入在老年代中。
老年代中采用的GC算法为标记-清除算法或者标记-整理算法。标记-清除算法为:首先标记出要进行GC的对象,标记完成后再进行GC。这种算法效率不高,并且会产生很多内存碎片。标记-整理算法:同样是先对要进行GC的对象进行标记,但是不同的是在标记完成后不是立刻执行GC,而是先将不需要GC的对象移动到一端,然后在边界外再对要回收的对象进行GC。
关于对象的分配:对象优先在Eden区域分配,大对象会直接进入老年代,长期存活的对象会进入老年代,这里的长期存活是根据新生代中的对象年龄阈值来定义的,对象刚分配到新生代的时候年龄为1,每进行一次GC对象的年龄会加1,HotSpot中默认的阈值是15,也就是说对象年龄达到15岁的时候会被分配到老年区,这个值是可以通过参数配置的。
在进行垃圾回收的时候新生代GC又叫minor GC,老年代GC可以设置内存容量达到百分比的多少的时候进行GC,老年代的GC又叫Full GC,minor GC时间短,频率高,而Full GC时间长,频率低。
2、方法区
方法区又被称为永久区,线程共享,是用来存储已被JVM加载的类信息、常量、静态变量、即时编译器编译后的代码等数据。方法区为堆的一个逻辑部分,但是在JDK1.7的HotSpot中已经将方法区中的字符串常量池移出,部分资料显示JDK1.8已经去除了方法区(不确定)。不过已经可以猜测此区域将会被本地内存逐步取代。
这个区域很少进行垃圾回收,回收目标主要是针对常量池的回收和对类型的卸载。
3、JVM栈
JVM栈是线程私有的,它的生命周期与线程相同。JVM栈描述的是java方法执行的内存模型,每个方法在执行的同时都会创建一个栈帧,用于存储局部变量表、操作数栈、动态链接、方法出口等信息。每个方法从调用直至执行完成的过程,就对应着一个栈帧在虚拟机栈中入栈到出栈的过程。
局部变量表中存放了编译期可知的各种基本数据类型、对象的引用类型。局部变量表中需要的内存空间在编译期间完成分配,当进入一个方法时,这个方法需要在帧中分配多大的局部变量空间是完全确定的,在方法运行期间不会改变局部变量表的大小。
4、本地方法栈
本地方法栈和JVM栈非常相似,它们之间的区别不过是jvm栈是为执行java方法服务,而本地方法栈是为jvm使用到对的本地方法服务。HotSpot虚拟机中直接把本地方法栈和JVM栈合二为一了。
5、程序计数器
程序计数器是一块较小的内存空间,线程私有。它可以看作是当前线程所执行的字节码的行号指示器。在jvm的概念模型里,字节码解释器工作就是通过改变这个计数器的值来选取下一条需要执行的字节码指令,分支、循环、跳转、异常处理、线程恢复等基础功能都需要依赖这个计数器来完成。
如果线程正在执行的是一个java方法,这个计数器记录的是正在执行的jvm字节码指令的地址;如果正在执行的是本地方法,这个计数器值则为空。
总结:
在jvm划分的内存区域中JVM栈和本地方法栈可能会抛出StackOverflowError异常和OutOfMemoryError异常。java堆和方法区可能会抛出OutOfMemoryError异常。程序计数器中没有地方规定会抛出这两个异常。
扩展:
在jvm规范中,StackOverflowError异常为:如果线程请求的栈深度大于JVM允许的栈深度,将抛出StackOverflowError异常。OutOfMemoryError异常:如果jvm可以动态扩展,如果扩展时无法申请到足够的内存,就会抛出OutOfMemoryError异常。
HotSpot虚拟机中标记要清除的对象方法不是使用引用计数器(有引用的时候计数器+1,引用失效-1,应用为0时回收),而使用的是可达性分析算法:以“GC Roots“的对象为起点,从这些节点开始向下搜索,搜索所走过的路径称为引用链,当一个对象到GC Roots没有任何引用链相连时,则证明这个对象不可达,即这个对象不可用,所以这个对象会被判定为是可回收对象。
标记-清除算法处理前后:
复制算法处理前后:
标记-整理算法处理前后:


- JVM初探- 内存分配、GC原理与垃圾收集器
JVM初探- 内存分配.GC原理与垃圾收集器 标签 : JVM JVM内存的分配与回收大致可分为如下4个步骤: 何时分配 -> 怎样分配 -> 何时回收 -> 怎样回收. 除了在概念 ...
- JVM总结(二):JVM的内存分配策略
这节我们总结一下JVM中的内存分配策略.目录如下: 内存分配策略 对象优先在新生代Eden分配 大对象直接进入老年代 长期存活的对象将进入老年代 动态对象年龄判定 空间分配担保 内存分配策略 Java ...
- JVM的内存分配垃圾回收策略
之前看过<深入了解Java虚拟机>感觉容易忘,今天写一篇博客加深一下印象. JVM的内存分配和垃圾回收(GC)主要发生在Java堆中.而Java堆根据对象的存活时间可以分为新生代和老年代, ...
- 一夜搞懂 | JVM GC&内存分配
前言 本文已经收录到我的Github个人博客,欢迎大佬们光临寒舍: 我的GIthub博客 学习导图 一.为什么要学习GC&内存分配? 时代发展到现在,如今的内存动态分配与内存回收技术已经相当成 ...
- JVM的内存分配与垃圾回收策略
自动内存管理机制主要解决了两个问题:给对象分配内存以及回收分配给对象的内存. >>垃圾回收的区域 前面的笔记中整理过虚拟机运行数据区,再看一下这个区域: 注意在这个Runtime Data ...
- 浅谈JVM与内存分配
一.程序内存分配 初始内存分配 当一个程序准备运行时,它首先向java虚拟机要内存,但是java虚拟机本身没有权限,它只能向操作系统申请内存,此时java虚拟机会拥有一个初始内存, 此处额外说明一下e ...
- jvm对象内存分配
一.jvm简单结构图 1.jvm内存对象分配整体流程: 1.类加载子系统和方法区 类加载子系统负责从文件系统或者网络中加载Class信息,加载的类信息存放于一块称为方法区的内存空间.除了类的信息外, ...
- 【面试必备】小伙伴栽在了JVM的内存分配策略。。。
周末有小伙伴留言说上周面试时被问到内存分配策略的问题,但回答的不够理想,小伙伴说之前公号里看过这一块的文章的,当时看时很清楚,也知道各个策略是干嘛的,但面试时脑子里清楚,心里很明白,但嘴里就是说不清楚 ...
- 认识JVM的内存分配
当我们在JVM中运行一段程序代码,JVM初始运行的时候都会分配好Method Area(方法区)和Heap(堆),而JVM每遇到一个线程,就为其分配一个Program Counter Register ...
随机推荐
- Linux文件权限和访问模式
为了更加安全的存储文件,Linux为不同的文件赋予了不同的权限,每个文件都拥有下面三种权限: 所有者权限:文件所有者能够进行的操作 组权限:文件所属用户组能够进行的操作 外部权限(其他权限):其他用户 ...
- Hadoop单机模式安装-(3)安装和配置Hadoop
网络上关于如何单机模式安装Hadoop的文章很多,按照其步骤走下来多数都失败,按照其操作弯路走过了不少但终究还是把问题都解决了,所以顺便自己详细记录下完整的安装过程. 此篇主要介绍在Ubuntu安装完 ...
- 14.linux按键驱动程序(一)
按键驱动程序 本文学习主要包含按键硬件的实现.中断分层管理.按键定时器去抖.阻塞性驱动程序设计.这里面需要使用到混杂设备驱动和中断处理程序的内容. 一.创建按键混杂设备驱动模型 int key_ope ...
- 传参数应该用哪种形式——值、引用、指针?
类型:C++ & Qt4,创建时间:十二月 30, 2011, 7:43 p.m. 标题无"转载"即原创文章,版权所有.转载请注明来源:http://hgoldfish.c ...
- Java_新浪微博SDK_jar包下载
新浪微博开放平台API_jar包下载地址:jar包(猛戳) --by HsuChan
- OGNL的使用
访问Action中的普通属性: <s:property value="loginname"/><br/> 访问Action中的对象属性: <s:pro ...
- Angular动画(ng-class)
ng-class 同 触发的是 addClass//当给元素添加一个class时触发, removeClass //把元素的class移除时触发 <ul ng-style="ulWid ...
- orm映射 封装baseDao
是用orm映射封装自己封装dao层 思路:通过映射获得实体类的属性拼接sql语句 import java.lang.reflect.Field; import java.lang.reflect.In ...
- 基于Proteus仿真的Arduino学习(2)——LED点阵探究A(LED点阵基础)
一.前言: 随着LED的普及,以LED点阵为基础的显示设置层出不穷.例如,公交车的线路提示牌.高速公路的信息提示牌,安装在大楼上的广告屏幕等.下面,我们将由简单到复杂地探索各种LED点阵的使用方法,同 ...
- c#去除List中的重复项
List<string> list = new List<string> {"a", "a", "b", " ...