java虚拟(一)--java内存区域和常量池概念
一、java运行时数据区
也可以称为java内存区域,和java内存模型不是一回事,不要弄混,这里基于jdk1.8之前
1.1、方法区
线程共享,类装载过程中产生的java.lang.Class对象保存在方法区,而不是堆,请参考《深入理解java虚拟机》P215
jdk1.8之前HotSpot通过永久带实现方法区,为了把GC可以像堆一样管理内存,能够复用代码,1.8移除永久带,通过本地内存实现方法区,
其他虚拟机没有永久带的概念,因为更容易出现内存溢出
主要存放类信息、常量、静态变量、即时编译后的代码等
垃圾回收主要是针对常量池回收和类型的卸载,这块区域的回收很难,尤其是类型卸载,可以选择不进行垃圾回收,但是回收很有必要的
PS:jdk1.8及以后,方法区被移除,通过元空间实现,而元空间使用的是直接内存,可以使用参数:-XX:MetaspaceSize
来指定元数据区的大小
1.2、虚拟机栈
线程私有,生命周期和线程相同,每执行一个方法都会创建一个栈帧,从执行到结束,对应着栈帧在虚拟机栈的入栈到出栈过程,可以类比
数据结构中的栈,java方法两种返回方式:
1、return语句
2、抛出异常
这两种方式都会导致栈帧被弹出
栈帧:
保存着局部变量表、操作数栈、方法出入口等
局部变量表:
用来保存方法参数和返回值,也就是基本数据类型、对象的引用、returnAddress类型(指向一个字节码指令的地址)
double和long占用两个局部变量空间(variable slot),其余占用1个,slot空间大小在编译期间就确定,方法运行期间无法改变
PS:可能出现Stack OverflowError、OutOfMemoryError错误
1.3、本地方法栈
线程私有,和虚拟机栈相似,一个为Java方法服务,一个为了本地方法服务,本地方法栈中方法实现的语言、方式等没有规定,由具体的虚拟机
确定,在HotSpot中只有栈,没有虚拟机栈和本地方法栈的区别。
本地方法被执行的时候,在本地方法栈也会创建一个栈帧,用于存放该本地方法的局部变量表、操作数栈、动态链接、出口信息。
PS:可能出现Stack OverflowError、OutOfMemoryError错误
1.4、堆
线程共享,这是虚拟机内存最大的一块区域,也是GC的主要区域,几乎所有的对象和数组都保存在这里
内存回收的角度分为:
新生代:Eden Space、From Survivor、To Survivor
老年代:
1、主要用来保存大对象(可以通过-XX:PretenureSizeThreshold 设置大对象的阀值)
2、或者从新生代经过15次 minor GC存活下来的对象(-XX:MaxTenuringThreshold)
3、第二条不是绝对的,VM动态判断,如果Survivor空间中相同年龄所有对象大小的综合大于Survivor空间的一半,年龄大于或等于该
年龄的对象就可以直接进入老年代,无须等到MaxTenuringThreshold要求的年龄
默认Eden Space:From Survivor:To Survivor=8:1:1,可以通过-XX:SurvivorRatio调节,一般不需要新生代和老年代默认是1:2,
可以通过-XX:NewRatio调节
PS:进一步划分的目的是更好地回收内存,或者更快地分配内存。
1.5、程序计数器
线程私有,是一块很小的内存区域,记录着当前虚拟机字节码指令的地址(对于JNI,值为undefined),字节码解释器通过改变计数器的值来
选择下一条执行的字节码,分支、循环、跳转、异常处理、线程恢复等功能都要依靠计数器。
线程上下文切换的时候,为了能够恢复到正确的执行位置,需要每个线程都拥有一个独立的线程计数器,互不影响。
PS:唯一一个没有规定OOM的区域
1.6、直接内存
不属于Java内存区域,有可能出现OOM,jdk1.4出现了NIO,它可以通过Native函数库分配堆外内存,通过Java堆中的DirectByteBuffer对象
作为引用进行操作,在某些场景明显提高性能,以为避免了Java堆和Native堆来回复制数据。
直接内存的分配不受Java堆大小限制,而是收到本机总内存的限制。
1.7、本地内存
就是JMM的概念了,后面写JMM的时候再讲
二、常量池
2.1、字符串常量池
在HotSpot中通过StringTable类实现功能,StringTable是一个hash表,默认长度大小1009,被所有类共享。字符串常量由字符组成,保存在
StringTable上面。在jdk1.6当中,StringTable的长度是固定1009,如果存放在StringTable中的字符串很多,造成hash冲突的几率很大,链表过
长,当通过String.intern()查找String Pool时,性能就会降低。
在jdk1.7当中,StringTable的长度可以通过-XX:StringTableSize设置
存放的内容:
String.intern()主要是为了复用字符串常量,节省内存空间
在jdk1.6及以前的版本,存放的都是字符串常量,使用""声明的字符串都存储在这,例如:String str = "abc";
在jdk1.7之后,String.intern()发生变化,返回对象的引用,因此除了字符串常量,也可以存放堆中字符串常量的引用
PS:在jdk1.7之后,字符串常量池从方法区转移到堆中
2.2、class常量池
首先java代码通过javac编译成class文件,class文件中保存着类的相关信息(版本,类、字段、方法、接口等信息),除此之外,还有Class
常量池,用来存放编译器产生的各种字面量(Literal)和符号引用(Symbolic References),每个class文件都有一个class常量池。
字面量:1.String 2.基本数据类型 3.声明final的常量
符号引用:1.类和方法的全限定名(类似于com.cfets.**.**这种) 2.字段的名称和描述符 3.方法的名称和描述符
2.3、运行时常量池
就是class常量池被加载到方法区之后的版本,区别就是:字面量可以通过String.intern()动态添加,符号引用解析为直接引用(类加载的
解析阶段)
当类加载到内存之中,jvm会把class常量池的内存存放到运行时常量池,所以,运行时常量池也是每个class都有的。
符号引用:上述有说明。以一组符号来描述所引用的目标,只要能定位到目标,无论是任何形式的字面量,和jvm实现的内存布局无关。
直接引用:直接指向目标的指针、相对偏移量或者间接定位到目标的句柄,句柄和指针对应对象的访问定位方式,和jvm实现的内存布局有关。
PS:JDK1.7及之后版本的 JVM 已经将运行时常量池从方法区中移了出来,在 Java 堆(Heap)中开辟了一块区域存放运行时常量池
java虚拟(一)--java内存区域和常量池概念的更多相关文章
- Java中常用的内存区域
在Java中主要存在4块内存空间,这些内存空间的名称及作用如下. 1. 栈内存空间: 保存所有对象名称(更准确的说是保存了引用的堆内存空间的地址). 2. 堆内存空间: 保存每个对象的具体属性内容 ...
- java中的堆、栈、常量池
java中的堆.栈.常量池 分类: java2010-01-15 03:03 4248人阅读 评论(5) 收藏 举报 javastring编译器jvm存储equals Java内存分配: 1. 寄存器 ...
- 详细介绍Java中的堆、栈和常量池
下面主要介绍JAVA中的堆.栈和常量池: 1.寄存器 最快的存储区, 由编译器根据需求进行分配,我们在程序中无法控制. 2. 栈 存放基本类型的变量数据和对象的引用,但对象本身不存放在栈中,而是存放在 ...
- JVM学习笔记(一):Java虚拟机和虚拟机内存区域
为什么Java程序需要运行在虚拟机上 因为Java在设计之初的跨平台特性,我们知道Java程序是运行在Java虚拟机上的.如果你要问为什么Java程序要运行在虚拟机上,我可以反问你几个问题. 为什么买 ...
- Java虚拟机运行时内存区域简析
figure:first-child { margin-top: -20px; } #write ol, #write ul { position: relative; } img { max-wid ...
- 【java】JVM的内存区域划分
学过C语言的朋友都知道C编译器在划分内存区域的时候经常将管理的区域划分为数据段和代码段,数据段包括堆.栈以及静态数据区.那么在Java语言当中,内存又是如何划分的呢? 由于Java程序是交由JVM执行 ...
- java运行时的内存区域
1.概述 java虚拟机在执行java程序的过程中会把它所管理的内存划分为若干个不同的数据区域. 这些区域都有各自的用途,以及创建和销毁的时间,有的区域随着虚拟机进程的启动而存在,有些区域则依赖用户线 ...
- java中的常用内存区域总结
<开发实战经典> (1)栈内存空间:保存所有的对象名称 (2)堆内存空间:保存每个对象的具体属性内容 (3)全局数据区:保存static类型的属性 (4)全 ...
- Java内存中的常量池
1,java内存模型简介 <深入理解java虚拟机>里将java内存分为如下五个模块: 堆-堆是所有线程共享的,主要用来存储对象. 其中,堆可分为:新生代和老年代两块区域.使用NewRat ...
随机推荐
- C语言中结构体变量之间赋值
近期,我阅读了某新员工小刘写的C语言代码,发现其对结构体变量之间的赋值不是非常熟悉. 对于两个同样类型的结构体变量,他均採用的是逐个成员变量直接赋值的形式.例如以下的代码演示样例: 如上代码所看到的, ...
- RELU 激活函数及其他相关的函数
RELU 激活函数及其他相关的函数 转载 2016年07月21日 20:51:17 45778 本博客仅为作者记录笔记之用,不免有很多细节不对之处. 还望各位看官能够见谅,欢迎批评指正. 更多相关博客 ...
- UVA - 11374 Airport Express (Dijkstra模板+枚举)
Description Problem D: Airport Express In a small city called Iokh, a train service, Airport-Express ...
- cocos2d-x 求相交矩阵
cocos2d-x有推断矩阵相交的方法 CCRect::intersectsRect(CCRect& rect)但可惜没有提供求两个相交矩阵的方法,我作了总结,代码例如以下: CCRect T ...
- DBCP,C3P0,Tomcat_JDBC 性能及稳定性測试
原创文章,转载请指明出处:http://aub.iteye.com/blog/1404219, 尊重他人即尊重自己 DBCP,C3P0,Tomcat_JDBC 性能及稳定性測试 1.測试环境: 硬件环 ...
- SpringMVC_RESTRUL_CRUD
编写POJO Departmet: package org.springmvc.curd.entity; public class Department { private int id; priva ...
- nginx开发(二)配置mp4文件在线播放
1: 第一步先开打nginx的文件夹遍历功能 vi /usr/local/nginx/conf/nginx.conf #编辑配置文件,在http {下面添加以下内容: autoindex on; #开 ...
- softmax function in c++
#include <iostream> #include <vector> #include <cmath> #include <algorithm> ...
- Django day 36 支付宝支付,微信推送
一:支付宝支付, 二:微信推送
- Akka源码分析-Akka-Streams-概念入门
今天我们来讲解akka-streams,这应该算akka框架下实现的一个很高级的工具.之前在学习akka streams的时候,我是觉得云里雾里的,感觉非常复杂,而且又难学,不过随着对akka源码的深 ...