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 此外常见的内存溢出有以 ...
随机推荐
- XML技术思想
百科名片: 可扩展标记语言 (Extensible Markup Language, XML) ,用于标记电子文件使其具有结构性的标记语言,可以用来标记数据.定义数据类型,是一种允许用户对自己的标记语 ...
- 13 Tensorflow API主要功能
要想使用Tensorflow API,首先要知道它能干什么.Tensorflow具有Python.C++.Java.Go等多种语言API,其中Python的API是最简单和好用的. Tensor Tr ...
- java web路径和spring读取配置文件
此篇博客缘起:部署java web系统到阿里云服务器(ubuntu14.04)的时候,有以下两个问题 找不到自定义的property配置文件 上传图片的时候找不到路径 开发的时候是在windows上的 ...
- Android AIDL 实例
为使应用程序之间能够彼此通信,Android提供了IPC (Inter Process Communication,进程间通信)的一种独特实现: AIDL (Android Interface Def ...
- [转]从minio中读取文件流进行下载文件
本文转自:https://blog.csdn.net/ZHANGLIZENG/article/details/82892678 一.获取Minio连接 public static String ...
- C#基础知识总结(五)
摘要 其他的数据类型:常量.枚举(enum).结构(struct).数组一.常量 语法:const 类型 变量名 = 变量值 常量称之为值不可变的变量! 在定义的地方赋值,其他的地方不能赋值. 常量变 ...
- No application encryption key has been specified.
环境:php7.1.10laravel5.5出现: 解决:在根目录下执行: php artisan key:generate OK问题解决
- Http(s)与后台交互方式
前言 Http(s)是前后端交互的主要方式之一,交互技术主要有:Ajax(XMLHttpRequest).Fetch.地址跳转(window.open.location.href).Http(s)与后 ...
- check约束
-- 删除表 drop table check_test; -- 不为空,不为null的值只能是0,1(不为空,值只能是0,1) create table check_test( default_fl ...
- struts2框架-----Action
控制器Action Action对象是struts2框架的核心,每个URL映射到特定的Action,其提供处理来自用户的请求所需要的处理逻辑.Action有两个重要的功能,即将数据从请求传递到视图和协 ...