Java的内存 -JVM 内存管理
一.综述
如果你学过C或者C++,那么你应该感受过它们对内存那种强大的掌控力。但是强大的能力往往需要更强大的控制力才能保证能力不被滥用,如果滥用C/C++的内存管理那么很容易出现指针满天飞的情况,不出问题还好,一出问题debug起来简直让人头疼得不要不要的。借用一句话,“指针一时爽,重构火葬场”。
而对java程序员来说,则没有这样的烦恼,因为java直接将内存管理交由jvm来管理,这样程序员在编写程序的时候就不用担心内存的使用情况而可以专注内容的实现。但这其实也造成了一点隐患,如果你不了解jvm内存管理的机制,很可能会因一些错误的代码写法而导致内存泄漏或内存溢出。
注:所述内容取自Jdk1.6。
二.jvm内存结构

三.每部分存储了哪些数据
1.程序计数器
程序计数器是一块较小的内存空间,可以看作当前线程所执行字节码的行号指示器,即指向正在执行的字节码。在概念模型中,字节码解释器的工作就是通过改变这个程序计数器的值来选取下一条字节码的指令。
值得一提的是,因为java的多线程是通过线程轮流切换并分配处理器执行时间来实现的(即一个小的时间段内仍然只有一个线程处于运行状态),每个线程的执行指令都不一样,为了使线程切换后能正确执行到该线程的下一指令,每个线程都需要一个独立的程序计数器,所以程序计数器使线程私有的。
2.虚拟机栈
虚拟机堆和虚拟机栈可以说是jvm内存中最值得我们关注的两块内存区域。虚拟机栈是内存私有的,每个方法在执行的同时会创建一个栈帧。用于存储局部变量表,操作数栈,动态链接等信息。每一个方法调用到执行完成的过程,其实就是对应一个栈帧在虚拟机栈中入栈到出栈的过程。
在这个区域可能出现的异常情况有两种,分别是StackOverflowError和OutOfMemoryError。当栈动态拓展过深,比如无限递归时会出现StackOverflowError,而当无法申请到足够内存时,则发生OutOfMemoryError。
3.堆
对大部分应用来说,堆是jvm管理的内存中最大的一块。与虚拟机栈不同,堆是被所有线程共享的。它的作用是存放对象的实例,几乎所有的对象实例都在这里分配内存。
堆同时也是垃圾收集器管理的主要区域,从内存回收的角度看,java堆可以分为“新生代”和“老年带”。
java堆可以处于物理上不连续的内存空间中,只需要其是逻辑上连续的即可,如我们的磁盘空间。当在堆中无法申请到足够的内存空间时,会抛出OutOfMemoryError。
在JDK1.6之前,字符串常量池一直放在方法区中,但是到了jdk1.7的时候,常量池便被移出方法区,而转到Java堆中区了。
在HotSpot虚拟机里实现的字符串常量池功能的是一个StringTable类,它是一个Hash表。这个哈希表在每个HotSpot虚拟机的实例只有一份,被所有的类共享。字符串常量由一个一个字符组成,并且相同字符串只保留一份。
HotSpot虚拟机的说明如下:
Area: HotSpot
Synopsis: In JDK 7, interned strings are no longer allocated in the permanent generation of the Java heap, but are instead allocated in the main part of the Java heap (known as the young and old generations), along with the other objects created by the application. This change will result in more data residing in the main Java heap, and less data in the permanent generation, and thus may require heap sizes to be adjusted. Most applications will see only relatively small differences in heap usage due to this change, but larger applications that load many classes or make heavy use of the String.intern() method will see more significant differences.
RFE: 6962931
大意便是说JDK1.7中的字符串不会再分配到Java的永久代中,而是分配到Java堆中。这意味着更多的数据将存于堆中而更少的数据存于方法区,这导致堆大小需要调整以做适配。由于此更改,大多数应用程序只会看到堆使用中的相对较小的差异,较大型的应用可能会发现其显著差异
4.方法区
与java堆一样,方法区也是所有线程共享的。它主要的功能时存储虚拟机加载的类信息,常量,静态变量,编译后的代码数据等。可以明显发现,方法区存放的这些数据都是比较难以被回收的,所以这个区的垃圾回收行为较少发生。
若在方法区中无法申请到足够的内存时,将会抛出OutOfMemoryError。
另外方法区中有一个运行时常量池。注意这里不是字符串常量池,它存储的是类编译时期生成的各种字面量和符号引用,并且每个类都有一个。
这里介绍一下什么是字面量和符号引用:
- 字面量包括:1.文本字符串 2.八种基本类型的值 3.被声明为final的常量等;
- 符号引用包括:1.类和方法的全限定名 2.字段的名称和描述符 3.方法的名称和描述符。
四.内存溢出和内存泄漏
内存溢出很好理解,就是发生OutOfMemoryError,比如当Java堆中新建了太多实例,耗完内存后就会发生内存溢出。比如如下实例代码:
public class HeapOOM{
static class OOMObject{}
public static void main(String[] args){
List<OOMObject> list = new ArrayList<OOMObject>();
while(true){
list.add(new OOMObject());
}
}
}
由于无限循环不断新建对象,最终会导致内存溢出。
那么内存泄漏呢?
内存泄漏的原因主要是一个对象已经不再需要使用,但被另一个长对象持有时,就有可能发生内存泄漏。比如在方法内一个对象被全局的HashMap持有,方法执行结束没有释放就会导致内存泄漏。
再有就是当一个对象被存储进HashSet后,其hashcode计算相关的变量被修改了,这也有可能导致内存泄漏,因为这时候这个对应基本已经不可达了。
Java的内存 -JVM 内存管理的更多相关文章
- java虚拟机学习-JVM内存管理:深入垃圾收集器与内存分配策略(4)
Java与C++之间有一堵由内存动态分配和垃圾收集技术所围成的高墙,墙外面的人想进去,墙里面的人却想出来. 概述: 说起垃圾收集(Garbage Collection,下文简称GC),大部分人都把这项 ...
- java虚拟机学习-JVM内存管理:深入Java内存区域与OOM(3)
概述 Java与C++之间有一堵由内存动态分配和垃圾收集技术所围成的高墙,墙外面的人想进去,墙里面的人却想出来. 对于从事C.C++程序开发的开发人员来说,在内存管理领域,他们即是拥有最高权力的皇帝又 ...
- Java虚拟机:JVM内存分代策略
版权声明:本文为博主原创文章,转载请注明出处,欢迎交流学习! Java虚拟机根据对象存活的周期不同,把堆内存划分为几块,一般分为新生代.老年代和永久代(对HotSpot虚拟机而言),这就是JVM的内存 ...
- 【java虚拟机】jvm内存模型
作者:pengjunlee原文链接:https://blog.csdn.net/pengjunlee/article/details/71909239 目录 一.运行时数据区域 1.程序计数器 2.J ...
- 深入理解Java虚拟机之JVM内存布局篇
内存布局**** JVM内存布局规定了Java在运行过程中内存申请.分配.管理的策略,保证了JVM的稳定高效运行.不同的JVM对于内存的划分方式和管理机制存在部分差异.结合JVM虚拟机规范,一起来 ...
- JAVA系列之JVM内存调优
一.前提 JVM性能调优牵扯到各方面的取舍与平衡,往往是牵一发而动全身,需要全盘考虑各方面的影响.在优化时候,切勿凭感觉或经验主义进行调整,而是需要通过系统运行的客观数据指标,不断找到最优解.同时,在 ...
- java 深入理解jvm内存模型 jvm学习笔记
jvm内存模型 这是java堆和方法区内存模型 参考:https://www.cnblogs.com/honey01/p/9475726.html Java 中的堆也是 GC 收集垃圾的主要区域.GC ...
- 深入理解Java虚拟机(一)——JVM内存模型
文章目录 程序计数器 定义 作用 特点 Java虚拟机栈 定义 特点 本地方法栈 定义 Java堆 定义 特点 方法区 定义 特点 运行常量池 直接内存 总结 Java虚拟机的内存空间分为五个部分: ...
- tomcat增加内存 JVM内存调优
tomcat总是卡死,查看日志catalina.out 发现疯狂报错 如下,提示内存溢出 java.lang.OutOfMemoryError: Java heap space 此外常见的内存溢出有以 ...
随机推荐
- sql server 性能调优之 当前用户请求分析 (1)
一. 概述 在生产数据库运行期间,有时我们需要查看当前用户会话状态或者是说数据库当前是否运行良好, 应用的场景比如:当运行的应用系统响应突然变慢时需要分析数据库的.或想分析当前的数据库是否繁忙,是否有 ...
- 自动测试工具(Jmeter,qtp等)
loadrunner.Selenium.QTP三者区别? Loadrunner是商业性能测试工具,收费,功能强大,适合做复杂场景的性能测试. Selenium是开源的web自动测试工具,免费 ...
- springboot 与 shiro 整合 (简洁版)
前言: 网上有很多springboot 与 shiro 整合的资料,有些确实写得很好, 对学习shiro和springboot 都有很大的帮助. 有些朋友比较省事, 直接转发或者复制粘贴.但是没有经过 ...
- 【转载】浅谈38K红外发射接受编码
转自Doctor_A 坛友的笔记! 之前做接触过一次红外遥控器,现在有空想用简单的话来聊一聊,下面有错误的地方欢迎改正指出: 1:红外的概念不聊,那是一种物理存在.以下聊38K红外发射接收,主要讲可编 ...
- 我们来说一说TCP神奇的40ms
本文由云+社区发表 TCP是一个复杂的协议,每个机制在带来优势的同时也会引入其他的问题. Nagel算法和delay ack机制是减少发送端和接收端包量的两个机制, 可以有效减少网络包量,避免拥塞.但 ...
- Ubuntu 安装网卡驱动
搭建Linux平台的无线热点,需要无线网卡和驱动都要支持 AP. 试了下Ubuntu平台默认驱动并不支持AP模式,所以需要更换驱动,具体操作步骤如下: 1.找到自己网卡芯片的型号,由于我的环境是搭建在 ...
- Python 与 Javascript 之比较
最近由于工作的需要开始开发一些Python的东西,由于之前一直在使用Javascript,所以会不自觉的使用一些Javascript的概念,语法什么的,经常掉到坑里.我觉得对于从Javascript转 ...
- 【SqlServer系列】数据库三大范式
1 概述 一般地,在进行数据库设计时,应遵循三大原则,也就是我们通常说的三大范式,即第一范式要求确保表中每列的原子性,也就是不可拆分:第二范式要求确保表中每列与主键相关,而不能只与主键的某部分相关 ...
- Perl中的执行上下文
perl中的上下文 在perl中,很多地方会切换上下文.所谓上下文,它的重点在于同一个表达式出现在不同地方,得到的结果不同.换句话说,同一个表达式,它表达的值不是固定的.这就像是同一个单词,在不同语境 ...
- [转]Cordova - 彻底搞定IOS编译!
本文转自:https://www.cnblogs.com/sunylat/p/9946482.html 操作系统:OSX10.14 XCode:10.1 Cordova:8.1.2 假设已经配置好了C ...