JVM内存简析
1.程序计数器:
这是一块较小的内存空间,它的作用可以看作是当前线程所执行的字节码的行号指示器,线程私有。
2.Java虚拟机栈:
它是Java方法执行的内存模型,每一个方法被调用到执行完成的过程,就对应着一个栈帧在虚拟机栈中从入栈到出栈的过程,线程私有。
3.本地方法栈:
和虚拟机栈类似,本地方法栈用于执行本地方法,线程私有。
4.Java堆:
该区域存在的唯一目的就是存放对象,几乎应用中所有的对象实例都在这里分配内存,所有线程共享。
5.方法区:
用于存储已被虚拟机加载的类信息、常量、静态变量、即时编译器编译后的代码等数据,所有线程共享。
内存分代:
一个应用启动,操作系统会给它分配一个初始的内存大小,这部分内存大部分应该属于堆内存,JVM为了更好地利用管理这部分内存,对该区域作了划分,一部分成为新生代,另一部分成为老年代。
一开始对象的创建都发生在新生代,随着对象的不断创建,如果新生代没有空间创建新对象,将会发生GC,这时的GC,位于新生代的对象每经过一次Minor GC后,如果这个对象没有被回收,则为自己的标记数加1,这个标记数用于标识这个对象经历了多少次的Minor GC,对于Sun 的Hotspot虚拟机,如果这个次数超过15,该对象才会被移动到老年代。
随着时间的推移,如果老年代也没有足够的空间容纳对象,老年代也会试着发起GC,这时的GC被称为Full GC。
相比Minor GC,Full GC 发生的次数比较少,但是每发生一次Full GC ,整个堆内存区域都需要执行一次垃圾回收,这对程序性能造成的影响比Minor GC大很多。所以我们应该尽量避免或者减少Full GC 的发生。
同时,在堆内存区域,发生最多的GC情形就是新生代的Minor GC了,因为所有的对象会优先去新生代开辟空间,所以这块内存变化很快,只有内存不够用,就会发生GC,但是一般的Minor GC执行比Full GC快很多。因为新生代和老年代的垃圾回收算法不一样。
垃圾回收算法:
标记-清除 算法 (Mask-Sweep)
这是最基础的收集算法,算法分为“标记”和“清除”两个阶段:
首先标记出所有需要回收的对象,在标记完成后统一回收掉所有被标记的对象。(之所以说它是最基础的收集算法,是因为后续的收集算法都是基于这种思路并对其缺点进行改进而得到的。)
他的主要缺点有两个:一个是效率问题,标记和清除过程的效率都不高;另外一个是空间问题,标记清除之后会产生大量不连续的内存碎片,空间碎片太多可能会导致当程序在以后的运行过程中需要分配较大对象时无法找到足够的连续内存而不得不提前出发另一次垃圾回收动作。
复制算法(Copying)
为了解决效率问题,一种称为“复制”(Copying)的收集算法出现了,它将可用内存按容量划分为大小相等的两块,每次只使用其中的一块。当这一块的内存用完了,就将还存活着的对象复制到另外一块上面,然后再把已使用过的内存空间一次清理掉。
这样使得每次都是对其中的一块进行内存回收,内存分配时也就不用考虑内存碎片等复杂情况,只要移动堆顶指针,按顺序分配内存即可,实现简单,运行高效。只是这种算法的代价是将内存缩小为原来的一半,未免太高了一点。但是这种算法的效率相当高,所以,现在的商业虚拟机都采用这种收集算法来回收新生代。为什么新生代可以使用复制算法呢?IBM 有专门研究表明,新生代中的对象 98% 都是朝生夕死,所以就不需要按照1:1的比例来划分内存空间。这里鉴于此,新生代采用了如下的划分策略。
现在把新生代再划分为三部分,一块较大的 Eden(伊甸园) 和两块较小的 Survivor(幸存者) 区域。
当回收时,将 Eden 和 Survivor 中还存活着的对象一次性地拷贝到另外一块Survivor空间上,最后清理掉Eden和刚才用过的Survivor的空间。HotSpot 虚拟机默认Eden和Survivor的大小比例是8∶1,也就是每次新生代中可用内存空间为整个新生代容量的90%(80%+10%),只有10%的内存是会被“浪费”的。这样清理完成后,原来的 Survivor 就空了,并一直保持为空,直到下次 Minor GC 时,它再作为存活对象的盛放地。两个 Survivor 就这样轮流当做 GC 过程中新生代存活对象的中转站。
但是,如果使用复制算法的内存区域有大量的存活对象时,复制算法就会变得捉襟见肘,这时需要更大的 Survivor 区用于盛放那些存活对象,甚至可能需要 1:1的比例。所以针对堆内存区域的老年代,就有了下面的算法。
标记-整理算法
标记过程仍然与“标记-清除”算法一样,但后续步骤不是直接对可回收对象进行清理,而是让所有存活的对象都向一端移动,然后直接清理掉端边界以外的内存。这种方法避免了碎片的产生,同时也不需要一块额外的内存空间,对于老年代会比较合适。但是相比复制算法,虽然该算法占用的内存空间少,但是耗费的垃圾回收时间会比复制算法久,所以上面也说了我们应该尽量避免或者减少 Full GC 的发生。这两种算法用精炼的语言描述就是
复制算法:用空间换时间
标记-整理算法:用时间换空间
一句话 鱼与熊掌不可兼得,但是针对新生代和老年代,他们都是最佳的选择。
总结
简单梳理一下文中讲到的一些知识点
为了更好的管理堆内存,该区域分为新生代和老年代。
新生代发生垃圾回收要比老年代频繁。
新生代发生的垃圾回收成为 Minor GC;老年代发生的 GC 成为 Full GC。
新生代使用复制算法进行垃圾回收;老年代使用标记-整理算法
为了更高效管理新生代的内存,按照复制算法,结合 IBM 的研究论证,新生代分为三块,一块比较大的 Eden 区和两块比较小的 Survivor 区,比例为 8:1:1
JVM内存简析的更多相关文章
- linux共享内存简析
共享内存是IPC的一种机制,允许两个不相关的进程共享同一块内存 //共享内存可以双向通信,但其本身没有相应机制,需要程序编写者设计,本例为单向通信(分为读端和写端). 共享内存读端: #include ...
- JAVA JVM常见内存参数配置简析
JVM常见内存参数配置简析 常见参数 -Xms .-Xmx.-XX:newSize.-XX:MaxnewSize.-Xmn(-XX:newSize.-XX:MaxnewSize) 简析 1.-Xm ...
- Linux内存管理机制简析
Linux内存管理机制简析 本文对Linux内存管理机制做一个简单的分析,试图让你快速理解Linux一些内存管理的概念并有效的利用一些管理方法. NUMA Linux 2.6开始支持NUMA( Non ...
- jvm内存增长问题排查简例
jvm内存增长问题排查 排查个jvm 内存占用持续增加的问题,纪录一下,引以为戒. 运维发现应用jvm内存占用在发布后回落,然后持续增高,,dump后分析一下: 占内存的大部分是这种名字相似的bean ...
- JDK框架简析--java.lang包中的基础类库、基础数据类型
题记 JDK.Java Development Kit. 我们必须先认识到,JDK不过,不过一套Java基础类库而已,是Sun公司开发的基础类库,仅此而已,JDK本身和我们自行书写总结的类库,从技术含 ...
- Flink源码阅读(一)——Flink on Yarn的Per-job模式源码简析
一.前言 个人感觉学习Flink其实最不应该错过的博文是Flink社区的博文系列,里面的文章是不会让人失望的.强烈安利:https://ververica.cn/developers-resource ...
- 简析 .NET Core 构成体系
简析 .NET Core 构成体系 Roslyn 编译器 RyuJIT 编译器 CoreCLR & CoreRT CoreFX(.NET Core Libraries) .NET Core 代 ...
- PHP的错误报错级别设置原理简析
原理简析 摘录php.ini文件的默认配置(php5.4): ; Common Values: ; E_ALL (Show all errors, warnings and notices inclu ...
- AFNetworking封装思路简析
http://blog.csdn.net/qq_34101611/article/details/51698473 一.AFNetworking的发展 1. AFN 1.0版本 AFN 的基础部分是 ...
随机推荐
- centos下node.js的安装
安装的路径我举例在home目录 1.cd /home 2.下载node.js最新版本 wget http://nodejs.org/dist/v0.10.28/node-v0.10.28.tar.gz ...
- Windows7下搭建Android开发环境
以后工作中要用到android开发,所以想搭建好开发环境,笔记本装的是win7 准备文件: 1 下载Android SDK http://code.google.com/android/downloa ...
- HTML5 学习笔记 表单属性
HTML5新的表单属性 HTML5 的form和input 标签添加了几个新的属性 <form>新属性 autocomplete novalidate input 新属性 autocomp ...
- jquery 鼠标拖动排序Li或Table
1.前端页面 <%@ Page Language="C#" AutoEventWireup="true" CodeFile="拖动排序Li或Ta ...
- Ubuntu安装deb软件包错误(依赖关系问题)解决
执行命令 sudo dpkg -i XXX.deb 返回依赖关系错误提示 执行 sudo apt-get -f install 这条命令将自动安装需要的依赖包. 再次执行命令 sudo dpkg -i ...
- JEECG技术总结
1.用户数据迁移时,必须在表t_s_base_user和t_s_user中都插入数据才会在页面显示.2.执行sql语句: String sql = "select count(id) fro ...
- javascript 相等运算符
相等运算符 JavaScript提供两个相等运算符:==和===. 简单说,它们的区别是相等运算符(==)比较两个值是否相等,严格相等运算符(===)比较它们是否为“同一个值”.如果两个值不是同一类型 ...
- RSA加密的测试demo
使用.net自带的RSA,需要引用System.Security.Cryptography 测试环境.net4.6 static void Main(string[] args) { var RSA ...
- python中unicode和unicodeescape
在python中,unicode是内存编码集,一般我们将数据存储到文件时,需要将数据先编码为其他编码集,比如utf-8.gbk等. 读取数据的时候再通过同样的编码集进行解码即可. #python3 & ...
- 2018.7.13vue知识小结
//配置是否允许vue-devtools检查代码,方便调试,生产环境中需要设置为false Vue.config.devtools=false; Vue.config.productionTip=fa ...