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内存简析的更多相关文章

  1. linux共享内存简析

    共享内存是IPC的一种机制,允许两个不相关的进程共享同一块内存 //共享内存可以双向通信,但其本身没有相应机制,需要程序编写者设计,本例为单向通信(分为读端和写端). 共享内存读端: #include ...

  2. JAVA JVM常见内存参数配置简析

    JVM常见内存参数配置简析   常见参数 -Xms .-Xmx.-XX:newSize.-XX:MaxnewSize.-Xmn(-XX:newSize.-XX:MaxnewSize) 简析 1.-Xm ...

  3. Linux内存管理机制简析

    Linux内存管理机制简析 本文对Linux内存管理机制做一个简单的分析,试图让你快速理解Linux一些内存管理的概念并有效的利用一些管理方法. NUMA Linux 2.6开始支持NUMA( Non ...

  4. jvm内存增长问题排查简例

    jvm内存增长问题排查 排查个jvm 内存占用持续增加的问题,纪录一下,引以为戒. 运维发现应用jvm内存占用在发布后回落,然后持续增高,,dump后分析一下: 占内存的大部分是这种名字相似的bean ...

  5. JDK框架简析--java.lang包中的基础类库、基础数据类型

    题记 JDK.Java Development Kit. 我们必须先认识到,JDK不过,不过一套Java基础类库而已,是Sun公司开发的基础类库,仅此而已,JDK本身和我们自行书写总结的类库,从技术含 ...

  6. Flink源码阅读(一)——Flink on Yarn的Per-job模式源码简析

    一.前言 个人感觉学习Flink其实最不应该错过的博文是Flink社区的博文系列,里面的文章是不会让人失望的.强烈安利:https://ververica.cn/developers-resource ...

  7. 简析 .NET Core 构成体系

    简析 .NET Core 构成体系 Roslyn 编译器 RyuJIT 编译器 CoreCLR & CoreRT CoreFX(.NET Core Libraries) .NET Core 代 ...

  8. PHP的错误报错级别设置原理简析

    原理简析 摘录php.ini文件的默认配置(php5.4): ; Common Values: ; E_ALL (Show all errors, warnings and notices inclu ...

  9. AFNetworking封装思路简析

    http://blog.csdn.net/qq_34101611/article/details/51698473 一.AFNetworking的发展 1. AFN 1.0版本 AFN 的基础部分是 ...

随机推荐

  1. python模块介绍-locustio:性能测试工具locustio

    转自:http://automationtesting.sinaapp.com/blog/m_locustio_doc python测试文章 http://weibo.com/cizhenshi?is ...

  2. 学习C#——性能计数器

    写在前面: 作为Web应用开发前线的一枚小兵,每看到“性能”一词总有种要亮瞎眼的感觉,说到“性能”那就不能不提“数据”,在程序猿.攻城师中不是流行这样一句话吗?“无图无真相”,谁要说谁开发的应用性能有 ...

  3. maven ArtifactTransferException:failure

    手动下载对应jar放在本地仓库 -> Update Dependencies(Maven4Myeclipse:eclipse上maven插件)

  4. Atitit.ALT+TAB没反应车and 点击任务栏程序闪烁但是不能切换

    Atitit.ALT+TAB没反应车and 点击任务栏程序闪烁但是不能切换 1. 可能你的Alt+Tab键被别人禁用了,试下下面的方法: 1 2. 为什么要禁用Alt+Tab 1 3. ALT+TAB ...

  5. Java类的实例化的初始化过程

    A a = new A(); new 创建对象过程: 1.类加载     代码验证 2.给对象在内存(堆)中分配空间(给属性赋值): 3.属性赋默认值: byte,short.int,long -&g ...

  6. js生成二维码的jquery组件–qrcode

    js生成二维码的jquery组件–qrcode 2015/01/30 / 2508 VIEWS / JAVASCRIPT, JQUERY 有一些耗cpu的计算,完全可以在客户端上计算,比如生成二维码. ...

  7. C++之虚析构函数

    代码一. #include <iostream> using namespace std; class Base { public: Base(){}; ~Base() { cout &l ...

  8. 基础地图Android SDK

    开发者可利用SDK提供的接口,使用百度为您提供的基础地图数据.目前百度地图SDK所提供的地图等级为3-21级,所包含的信息有建筑物.道路.河流.学校.公园等内容. V3.7.0起,地图支持缩放至21级 ...

  9. dp之多重背包poj2392

    题意:有k种石头,高为hi,在不超过ai的高度下,这种石头可以放置,有ci种这个石头,求这些石头所能放置的最高高度......... 思路:以往的什么硬币种数,最大硬币数之类的,他们的硬币都已经是排好 ...

  10. am335x alsa codec调试

    root@phyCORE-AM335x:~ aplay -l**** List of PLAYBACK Hardware Devices ****card 0: audio [PCM051 audio ...