1.内存模型概述

  

2.运行时数据区

2.1.程序计数器

  理解:

  1.什么是程序计数器

  2.线程私有还是共享

  引入难点:

  理解什么是 native方法

 简单地讲,一个Native Method就是一个java调用非java代码的接口。
一个Native Method是这样一个java的方法:该方法的实现由非java语言实现,比如C。
这个特征并非java所特有,很多其它的编程语言都有这一机制,比如在C++中,你可以用extern "C"告知C++编译器去调用一个C的函数。
"A native method is a Java method whose implementation is provided by non-java code."
在定义一个native method时,并不提供实现体(有些像定义一个java interface),因为其实现体是由非java语言在外面实现的。,下面给了一个示例:
public class IHaveNatives
{
native public void Native1( int x ) ;
native static public long Native2() ;
native synchronized private float Native3( Object o ) ;
native void Native4( int[] ary ) throws Exception ;
}

2.2.java虚拟机栈

  https://www.cnblogs.com/newAndHui/p/11168791.html

2.3.本地方法栈

  本地方法栈(Native Method Stack) 与虚拟机栈所发挥的作用是相似的,

  他们之间的区别是:

  1.虚拟机栈为虚拟机执行java方法(也就是字节码)服务;

  2.本地方法栈则为虚拟机使用的Native方法服务.

  与虚拟机方法一样,本地方法栈区域也会就抛出StackOverflowError 和  OutOfMemoryErrory异常.

2.4.java堆

  

  1. Java堆是被所有线程共享的一块内存区域,在虚拟机启动时创建,是虚拟机所管理的内存中最大的一块。

此内存区域的唯一目的就是【存放对象实例和数组】,几乎所有的对象实例和数组都在这里分配内存。

  2. Java堆是垃圾收集器管理的主要区域,也称为GC 垃圾堆。后面会专门讲解GC算法。

  从内存回收的角度看,由于现在收集器基本都采用分代收集算法,所以Java堆可以细分为:新生代、老生代;

  从内存分配的角度看,线程共享的Java堆可能划分出多个线程私有的分配缓冲区(TLAB);

  不论如何划分,都与存放的内容无关,无论哪个区域,存储的仍然是对象实例和数组。

  3. 如果在堆中没有内存完成实例分配,并且堆上也无法再扩展时,将会抛出OutOfMemoryError异常。

  4. 内存泄露和内存溢出

  内存溢出 out of memory,是指程序在申请内存时,没有足够的内存空间供其使用,出现out of memory;

  内存泄露 memory leak,是指程序在申请内存后,无法释放已申请的内存空间,一次内存泄露危害可以忽略,但内存泄露堆积后果很严重,无论多少内存,迟早会被占光。

  内存泄漏的累积最终会导致内存溢出!

  案例演示:

  参看:https://www.cnblogs.com/newAndHui/p/11105956.html 的 2.4节 内存快照分析

2.5.方法区

  

  1. 和堆一样,是各个线程共享的内存区域。它用于存储已被虚拟机加载的类信息、常量、静态变量、即时编译器编译后的代码等数据。

  2. Java虚拟机规范对方法区的限制非常宽松,除了和Java堆一样 不需要连续的内存和可以选择固定大小或者可扩展之外,还可以选择不实现垃圾回收。

  这区域的内存回收目标主要是针对常量池的回收和类型的卸载,

  一般而言,这个区域的内存回收比较难以令人满意,尤其是类型的回收,条件相当苛刻,但是这部分区域的内存回收确实是必要的。

  3. 很多开发者更愿意把方法区称为“永久代”(Perm Gen)(Permanent Generation)「总是存放不会轻易改变的内容」,

  原因:HotSpot的方法区也是采用的GC分代垃圾收集,省去了专门为方法区编写内存管理的工作。

  在目前已经发布的JDK 1.7 的HotSpot中,已经把原本放在永久代(方法区)的字符串常量池移至堆中。

  4. 运行时常量池(Runtime Constant Pool)是方法区的一部分(已移走)。

  5.JDK 1.8 中,已经没有方法区(永久代),而是将方法区直接放在一个与堆不相连的本地内存区域(Native Memory),这个区域被叫做元空间。

  6.当无法满足内存分配需求时:将会抛出OutOfMemoryError异常

2.6运行时常量池

  

  1. 运行时常量池是方法区的一个部分

  2. Class文件中除了有类的版本、字段、方法、接口等描述信息外,还有一项信息是常量池(Constant Pool Table),用于存放编译期生成的字面量和符号引用,

  这部分内容(也可以称为 .Class文件中的静态常量池)将在类加载后进入方法区的运行时常量池中存放。

  字面量 : 比较接近Java语言层面的常量概念,如文本字符串、声明为final的常量值等。(final修饰的成员变量和类变量!「类变量即静态(成员)变量)」,也就是除final修饰的局部变量。

  符号引用 : 属于编译原理方面的概念,包括
    1.类和接口的全限定名(即路径,包名+类名)。
    2.字段的名称和描述符。
    3.方法的名称和描述符。
  当虚拟机运行时,需要从常量池获得对应的符号引号,再在类创建或运行时解析、翻译到具体的内存地址之中(直接引用)。

  3. 除了保存Class文件中描述的符号引用外,还会把编译出来的直接引用也存储在运行时常量池中。

  4. Java语言并不要求常量一定只有编译期才能生成,也就是并非置入Class文件中常量池的内容才能进入方法区运行时常量池,

  运行期间也可能将新的常量放入池中,这种特性被开发人员利用得比较多的便是String 类的intern()方法。

  5. 当常量池无法再申请到内存时也会抛出OutofMemoryError异常。

2.7直接内存

  

  1.并不是虚拟机运行时数据区的第一部分
  2.也不是java虚拟机规范中定义的内存区域
  3.直接内存分配不会受到java堆大小的限制,但受到本机总内存限制
  4.用处:直接使用Native函数分配该内存
  5.抛出OutofMemoryError异常

2.8扩展

  成员变量与局部变量

  成员变量 : 方法外部,类内部定义的变量;

  局部变量 : 方法或语句块内部定义的变量,必须初始化。

  1. 形参是局部变量,实参则可能是方法中的局部变量或全局变量。
  2. 栈内存中的局部变量随方法而生,随方法而灭。
  3. 成员变量存储在堆中的对象里,由垃圾收集器回收。

  

参考文献:

<<深入理解Java虚拟机:JVM高级特性与最佳实践>>

深入理解JVM-java内存区域与内存溢出异常的更多相关文章

  1. 深入理解jvm之内存区域与内存溢出

    文章目录 1. Java内存区域与内存溢出异常 1.1. 运行时数据区域 1.1.1. 程序计数器 1.1.2. java虚拟机栈 1.1.3. 本地方法栈 1.1.4. Java堆(Java Hea ...

  2. 深入理解java虚拟机系列(一):java内存区域与内存溢出异常

    文章主要是阅读<深入理解java虚拟机:JVM高级特性与最佳实践>第二章:Java内存区域与内存溢出异常 的一些笔记以及概括. 好了開始.假设有什么错误或者遗漏,欢迎指出. 一.概述 先上 ...

  3. 深入理解JVM之JVM内存区域与内存分配

    深入理解JVM之JVM内存区域与内存分配 在学习jvm的内存分配的时候,看到的这篇博客,该博客对jvm的内存分配总结的很好,同时也利用jvm的内存模型解释了java程序中有关参数传递的问题. 博客出处 ...

  4. 深入理解java虚拟机-第二章:java内存区域与内存泄露异常

    2.1概述: java将内存的管理(主要是回收工作),交由jvm管理,确实很省事,但是一点jvm因内存出现问题,排查起来将会很困难,为了能够成为独当一面的大牛呢,自然要了解vm是怎么去使用内存的. 2 ...

  5. 深入理解java虚拟机---->java内存区域与内存溢出异常

    2. java内存区域于内存溢出异常 2.1 概述: 对于C/C++而言,内存管理具有最高的权利,既拥有每一个对象的“所有权”,又担负着每一个对象生命开始到结束的维护责任. 对于java而言,则把内存 ...

  6. 深入理解Java虚拟机之Java内存区域与内存溢出异常

    Java内存区域与内存溢出异常 运行时数据区域 程序计数器 用于记录从内存执行的下一条指令的地址,线程私有的一小块内存,也是唯一不会报出OOM异常的区域 Java虚拟机栈 Java虚拟机栈(Java ...

  7. 深入理解Java虚拟机之图解Java内存区域与内存溢出异常

    Java内存区域与内存溢出异常 运行时数据区域 程序计数器 用于记录从内存执行的下一条指令的地址,线程私有的一小块内存,也是唯一不会报出OOM异常的区域 Java虚拟机栈 Java虚拟机栈(Java ...

  8. 《深入理解java虚拟机》第二章 Java内存区域与内存溢出异常

    第二章 Java内存区域与内存溢出异常 2.2 运行时数据区域  

  9. 第二章Java内存区域与内存溢出异常

    第二章 Java内存区域与内存溢出异常 一.概述 对与Java程序员来说,在虚拟机自动内存管理机制的帮助下,不再需要为每个new操作去写delete/free代码,不容易出现内存泄露和内存溢出问 题, ...

  10. JVM内存区域与内存溢出异常

    Java虚拟机在执行java程序时会把它所管理的内存会分为若干个不同的数据区域,不同的区域在内存不足时会抛出不同的异常. >>运行时数据区域的划分 (1)程序计数器程序计数器(Progra ...

随机推荐

  1. List containsKey 和Map contains 判断集合中是否包含某个值

    map集合 //1.第一种 HashMap map = new HashMap(); map.put("1", "value1"); map.put(" ...

  2. fashion MNIST识别(Tensorflow + Keras + NN)

    Fashion MNIST https://www.kaggle.com/zalando-research/fashionmnist Fashion-MNIST is a dataset of Zal ...

  3. Qt编写数据可视化大屏界面电子看板系统

    一.前言 目前大屏大数据可视化UI这块非常火,趁热也用Qt来实现一个,Qt这个一站式超大型GUI超市,没有什么他做不了的,大屏电子看板当然也不在话下,有了QSS和QPainter这两个无敌的工具组合, ...

  4. Egret自定义位图文字(自定义+BitmapLabel)

    一 自定位图文字 因为egret的位图文字是texturemerger做的,需要多张单图片导入tm,然后导出两个文件来使用,过程比较麻烦. 而Laya的位图文字则是一张整图数字图片,使用FontCli ...

  5. shell中函数的使用

    函数是一个脚本代码块,你可以对它进行自定义命名,并且可以在脚本中任意位置使用这个函数.如果想要这个函数,只要调用这个函数的名称就可以了.使用函数的好处在于模块化以及代码可读性强. (1).函数的创建语 ...

  6. 在条件判断中使用 all() / any()

    在条件判断中使用 all() / any() all() 和 any() 两个函数非常适合在条件判断中使用.这两个函数接受一个可迭代对象,返回一个布尔值,其中: all(seq):仅当 seq 中所有 ...

  7. jenkins自动化视频地址

    1.腾讯课堂的视频 http://www.ctnrs.com/study.html 我的课程所有列表 2.百度网盘里面的

  8. csu 1984: LXX的能力值

    1984: LXX的能力值 Submit Page   Summary   Time Limit: 3 Sec     Memory Limit: 128 Mb     Submitted: 17   ...

  9. 【记录】【springboot】动态定时任务ScheduledFuture,可添加、修改、删除

    这里只演示添加和删除任务的,因为修改就是删除任务再添加而已. 方便演示,任务就是每3秒打印 1.没有任务 后台 2.添加一个任务 3.再添加一个任务 4.删除一个任务 5.再添加一个任务 6.代码 运 ...

  10. 【记录】【MySQL】填充字符串函数 LPAD(str,len,padstr)

    LPAD(str,len,padstr) 1.如果str的长度等于len,那么就返回str 2.如果str的长度大于len,那么就返回str的前len个长度 3.如果str的长度小于len,那么就返回 ...