深入理解JVM-java内存区域与内存溢出异常
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扩展
成员变量与局部变量
成员变量 : 方法外部,类内部定义的变量;
局部变量 : 方法或语句块内部定义的变量,必须初始化。
- 形参是局部变量,实参则可能是方法中的局部变量或全局变量。
- 栈内存中的局部变量随方法而生,随方法而灭。
- 成员变量存储在堆中的对象里,由垃圾收集器回收。
参考文献:
<<深入理解Java虚拟机:JVM高级特性与最佳实践>>
深入理解JVM-java内存区域与内存溢出异常的更多相关文章
- 深入理解jvm之内存区域与内存溢出
文章目录 1. Java内存区域与内存溢出异常 1.1. 运行时数据区域 1.1.1. 程序计数器 1.1.2. java虚拟机栈 1.1.3. 本地方法栈 1.1.4. Java堆(Java Hea ...
- 深入理解java虚拟机系列(一):java内存区域与内存溢出异常
文章主要是阅读<深入理解java虚拟机:JVM高级特性与最佳实践>第二章:Java内存区域与内存溢出异常 的一些笔记以及概括. 好了開始.假设有什么错误或者遗漏,欢迎指出. 一.概述 先上 ...
- 深入理解JVM之JVM内存区域与内存分配
深入理解JVM之JVM内存区域与内存分配 在学习jvm的内存分配的时候,看到的这篇博客,该博客对jvm的内存分配总结的很好,同时也利用jvm的内存模型解释了java程序中有关参数传递的问题. 博客出处 ...
- 深入理解java虚拟机-第二章:java内存区域与内存泄露异常
2.1概述: java将内存的管理(主要是回收工作),交由jvm管理,确实很省事,但是一点jvm因内存出现问题,排查起来将会很困难,为了能够成为独当一面的大牛呢,自然要了解vm是怎么去使用内存的. 2 ...
- 深入理解java虚拟机---->java内存区域与内存溢出异常
2. java内存区域于内存溢出异常 2.1 概述: 对于C/C++而言,内存管理具有最高的权利,既拥有每一个对象的“所有权”,又担负着每一个对象生命开始到结束的维护责任. 对于java而言,则把内存 ...
- 深入理解Java虚拟机之Java内存区域与内存溢出异常
Java内存区域与内存溢出异常 运行时数据区域 程序计数器 用于记录从内存执行的下一条指令的地址,线程私有的一小块内存,也是唯一不会报出OOM异常的区域 Java虚拟机栈 Java虚拟机栈(Java ...
- 深入理解Java虚拟机之图解Java内存区域与内存溢出异常
Java内存区域与内存溢出异常 运行时数据区域 程序计数器 用于记录从内存执行的下一条指令的地址,线程私有的一小块内存,也是唯一不会报出OOM异常的区域 Java虚拟机栈 Java虚拟机栈(Java ...
- 《深入理解java虚拟机》第二章 Java内存区域与内存溢出异常
第二章 Java内存区域与内存溢出异常 2.2 运行时数据区域
- 第二章Java内存区域与内存溢出异常
第二章 Java内存区域与内存溢出异常 一.概述 对与Java程序员来说,在虚拟机自动内存管理机制的帮助下,不再需要为每个new操作去写delete/free代码,不容易出现内存泄露和内存溢出问 题, ...
- JVM内存区域与内存溢出异常
Java虚拟机在执行java程序时会把它所管理的内存会分为若干个不同的数据区域,不同的区域在内存不足时会抛出不同的异常. >>运行时数据区域的划分 (1)程序计数器程序计数器(Progra ...
随机推荐
- List containsKey 和Map contains 判断集合中是否包含某个值
map集合 //1.第一种 HashMap map = new HashMap(); map.put("1", "value1"); map.put(" ...
- fashion MNIST识别(Tensorflow + Keras + NN)
Fashion MNIST https://www.kaggle.com/zalando-research/fashionmnist Fashion-MNIST is a dataset of Zal ...
- Qt编写数据可视化大屏界面电子看板系统
一.前言 目前大屏大数据可视化UI这块非常火,趁热也用Qt来实现一个,Qt这个一站式超大型GUI超市,没有什么他做不了的,大屏电子看板当然也不在话下,有了QSS和QPainter这两个无敌的工具组合, ...
- Egret自定义位图文字(自定义+BitmapLabel)
一 自定位图文字 因为egret的位图文字是texturemerger做的,需要多张单图片导入tm,然后导出两个文件来使用,过程比较麻烦. 而Laya的位图文字则是一张整图数字图片,使用FontCli ...
- shell中函数的使用
函数是一个脚本代码块,你可以对它进行自定义命名,并且可以在脚本中任意位置使用这个函数.如果想要这个函数,只要调用这个函数的名称就可以了.使用函数的好处在于模块化以及代码可读性强. (1).函数的创建语 ...
- 在条件判断中使用 all() / any()
在条件判断中使用 all() / any() all() 和 any() 两个函数非常适合在条件判断中使用.这两个函数接受一个可迭代对象,返回一个布尔值,其中: all(seq):仅当 seq 中所有 ...
- jenkins自动化视频地址
1.腾讯课堂的视频 http://www.ctnrs.com/study.html 我的课程所有列表 2.百度网盘里面的
- csu 1984: LXX的能力值
1984: LXX的能力值 Submit Page Summary Time Limit: 3 Sec Memory Limit: 128 Mb Submitted: 17 ...
- 【记录】【springboot】动态定时任务ScheduledFuture,可添加、修改、删除
这里只演示添加和删除任务的,因为修改就是删除任务再添加而已. 方便演示,任务就是每3秒打印 1.没有任务 后台 2.添加一个任务 3.再添加一个任务 4.删除一个任务 5.再添加一个任务 6.代码 运 ...
- 【记录】【MySQL】填充字符串函数 LPAD(str,len,padstr)
LPAD(str,len,padstr) 1.如果str的长度等于len,那么就返回str 2.如果str的长度大于len,那么就返回str的前len个长度 3.如果str的长度小于len,那么就返回 ...