关于java8内存模型的信息

博主:adminadmin 2023-03-22 10:58:09 795

本篇文章给大家谈谈java8内存模型,以及对应的知识点,希望对各位有所帮助,不要忘了收藏本站喔。

本文目录一览:

Java基本数据类型?

一、基本数据类型:

byte:Java中最小的数据类型,在内存中占8位(bit),即1个字节,取值范围-128~127,默认值0

short:短整型,在内存中占16位,即2个字节,取值范围-32768~32717,默认值0

int:整型,用于存储整数,在内在中占32位,即4个字节,取值范围-2147483648~2147483647,默认值0

long:长整型,在内存中占64位,即8个字节-2^63~2^63-1,默认值0L

float:浮点型,在内存中占32位,即4个字节,用于存储带小数点的数字(与double的区别在于float类型有效小数点只有6~7位),默认值0

double:双精度浮点型,用于存储带有小数点的数字,在内存中占64位,即8个字节,默认值0

char:字符型,用于存储单个字符,占16位,即2个字节,取值范围0~65535,默认值为空

boolean:布尔类型,占1个字节,用于判断真或假(仅有两个值,即true、false),默认值false

二、Java数据类型基本概念:

数据类型在计算机语言里面,是对内存位置的一个抽象表达方式,可以理解为针对内存的一种抽象的表达方式。接触每种语言的时候,都会存在数据类型的认识,有复杂的、简单的,各种数据类型都需要在学习初期去了解,Java是强类型语言,所以Java对于数据类型的规范会相对严格。数据类型是语言的抽象原子概念,可以说是语言中最基本的单元定义,在Java里面,本质上讲将数据类型分为两种:基本类型和引用数据类型。

基本类型:简单数据类型是不能简化的、内置的数据类型、由编程语言本身定义,它表示了真实的数字、字符和整数。

引用数据类型:Java语言本身不支持C++中的结构(struct)或联合(union)数据类型,它的复合数据类型一般都是通过类或接口进行构造,类提供了捆绑数据和方法的方式,同时可以针对程序外部进行信息隐藏。

三、Java中的数据类型与内存的关系

在Java中,每个存放数据的变量都是有类型的,如:

charch;floatx;inta,b,c;

ch是字符型的,就会分配到2个字节内存。不同类型的变量在内存中分配的字节数不同,同时存储方式也是不同的。

所以给变量赋值前需要先确定变量的类型,确定了变量的类型,即确定了数据需分配内存空间的大小,数据在内存的存储方式。

四、Java数据类型在内存中的存储:

1)基本数据类型的存储原理:所有的简单数据类型不存在“引用”的概念,基本数据类型都是直接存储在内存中的内存栈上的,数据本身的值就是存储在栈空间里面,而Java语言里面八种数据类型是这种存储模型;

2)引用类型的存储原理:引用类型继承于Object类(也是引用类型)都是按照Java里面存储对象的内存模型来进行数据存储的,使用Java内存堆和内存栈来进行这种类型的数据存储,简单地讲,昆明北大青鸟认为“引用”是存储在有序的内存栈上的,而对象本身的值存储在内存堆上的。

JDK1.6、JDK1.7、JDK1.8 内存模型对比

如图25-1 是 JDK 1.6、1.7、1.8 的内存模型演变过程,其实这个内存模型就是 JVM 运行时数据区依照JVM虚拟机规范的具体实现过程。

JDK 1.6:程序计数器、Java虚拟机栈、本地方法栈、堆、方法区[永久代](字符串常量池、静态变量、运行时常量池、类常量池)

JDK 1.7:程序计数器、Java虚拟机栈、本地方法栈、堆(字符串常量、静态变量)、方法区[永久代](运行时常量池、类常量池)

JDK 1.8:程序计数器、Java虚拟机栈、本地方法栈、堆(字符串常量)、元数据(静态变量、运行时常量池、类常量池)

JDK 1.8 JVM 的内存结构主要由三大块组成:堆内存、元空间和栈,Java 堆是内存空间占据最大的一块区域。

Java 堆,由年轻代和年老代组成,分别占据1/3和2/3。

年轻代又分为三部分, Eden 、 From Survivor 、 To Survivor ,占据比例为8:1:1,可调。

元空间从虚拟机Java堆中转移到本地内存,默认情况下,元空间的大小仅受本地内存的限制,说白了也就是以后不会因为永久代空间不够而抛出OOM异常出现了。 jdk1.8以前版本的 class和JAR包数据存储在 PermGen下面 ,PermGen 大小是固定的,而且项目之间无法共用,公有的 class,所以比较容易出现OOM异常。

升级JDK 1.8后,元空间配置参数,-XX:MetaspaceSize=512M XX:MaxMetaspaceSize=1024M。

小技巧通过jps、jinfo查看元空间,如下:

通过jinfo查看默认MetaspaceSize大小(约20M),MaxMetaspaceSize比较大。

其他:关于JDK1.8 元空间的介绍:  Move part of the contents of the permanent generation in Hotspot to the Java heap and the remainder to native memory.

Java垃圾回收:GC在什么时候对什么做了什么

GC在什么时候对什么做了什么?

要回答这个问题,先了解下GC的发展史、jvm运行时数据区的划分、jvm内存分配策略、jvm垃圾收集算法等知识。

先说下jvm运行时数据的划分,粗暴的分可以分为堆区(Heap)和栈区(Stack),但jvm的分法实际上比这复杂得多,大概分为下面几块:

1、程序计数器(Program Conuter Register)

程序计数器是一块较小的内存空间,它是当前线程执行字节码的行号指示器,字节码解释工作器就是通过改变这个计数器的值来选取下一条需要执行的指令。它是线程私有的内存,也是唯一一个没有OOM异常的区域。

2、Java虚拟机栈区(Java Virtual Machine Stacks)

也就是通常所说的栈区,它描述的是Java方法执行的内存模型,每个方法被执行的时候都创建一个栈帧(Stack Frame),用于存储局部变量表、操作数栈、动态链接、方法出口等。每个方法被调用到完成,相当于一个栈帧在虚拟机栈中从入栈到出栈的过程。此区域也是线程私有的内存,可能抛出两种异常:如果线程请求的栈深度大于虚拟机允许的深度将抛出StackOverflowError;如果虚拟机栈可以动态的扩展,扩展到无法动态的申请到足够的内存时会抛出OOM异常。

3、本地方法栈(Native Method Stacks)

本地方法栈与虚拟机栈发挥的作用非常相似,区别就是虚拟机栈为虚拟机执行Java方法,本地方法栈则是为虚拟机使用到的Native方法服务。

4、堆区(Heap)

所有对象实例和数组都在堆区上分配,堆区是GC主要管理的区域。堆区还可以细分为新生代、老年代,新生代还分为一个Eden区和两个Survivor区。此块内存为所有线程共享区域,当堆中没有足够内存完成实例分配时会抛出OOM异常。

5、方法区(Method Area)

方法区也是所有线程共享区,用于存储已被虚拟机加载的类信息、常量、静态变量、即时编译后的代码等数据。GC在这个区域很少出现,这个区域内存回收的目标主要是对常量池的回收和类型的卸载,回收的内存比较少,所以也有称这个区域为永久代(Permanent Generation)的。当方法区无法满足内存分配时抛出OOM异常。

6、运行时常量池(Runtime Constant Pool)

运行时常量池是方法区的一部分,用于存放编译期生成的各种字面量和符号引用。

垃圾收集(Garbage Collection)并不是Java独有的,最早是出现在Lisp语言中,它做的事就是自动管理内存,也就是下面三个问题:

1、什么时候回收

2、哪些内存需要回收

3、如何回收

1、什么时候回收?

上面说到GC经常发生的区域是堆区,堆区还可以细分为新生代、老年代,新生代还分为一个Eden区和两个Survivor区。

1.1 对象优先在Eden中分配,当Eden中没有足够空间时,虚拟机将发生一次Minor GC,因为Java大多数对象都是朝生夕灭,所以Minor GC非常频繁,而且速度也很快;

1.2 Full GC,发生在老年代的GC,当老年代没有足够的空间时即发生Full GC,发生Full GC一般都会有一次Minor GC。大对象直接进入老年代,如很长的字符串数组,虚拟机提供一个-XX:PretenureSizeThreadhold参数,令大于这个参数值的对象直接在老年代中分配,避免在Eden区和两个Survivor区发生大量的内存拷贝;

1.3 发生Minor GC时,虚拟机会检测之前每次晋升到老年代的平均大小是否大于老年代的剩余空间大小,如果大于,则进行一次Full GC,如果小于,则查看HandlePromotionFailure设置是否允许担保失败,如果允许,那只会进行一次Minor GC,如果不允许,则改为进行一次Full GC。

2、哪些内存需要回收

jvm对不可用的对象进行回收,哪些对象是可用的,哪些是不可用的?Java并不是采用引用计数算法来判定对象是否可用,而是采用根搜索算法(GC Root Tracing),当一个对象到GC Roots没有任何引用相连接,用图论的来说就是从GC Roots到这个对象不可达,则证明此对象是不可用的,说明此对象可以被GC。对于这些不可达对象,也不是一下子就被GC,而是至少要经历两次标记过程:如果对象在进行根搜索算法后发现没有与GC Roots相连接的引用链,那它将会第一次标记并且进行一次筛选,筛选条件是此对象有没有必要执行finalize()方法,当对象没有覆盖finalize()方法或者finalize()方法已经被虚拟机调用执行过一次,这两种情况都被视为没有必要执行finalize()方法,对于没有必要执行finalize()方法的将会被GC,对于有必要有必要执行的,对象在finalize()方法中可能会自救,也就是重新与引用链上的任何一个对象建立关联即可。

3、如何回收

选择不同的垃圾收集器,所使用的收集算法也不同。

在新生代中,每次垃圾收集都发现有大批对象死去,只有少量存活,则使用复制算法,新生代内存被分为一个较大的Eden区和两个较小的Survivor区,每次只使用Eden区和一个Survivor区,当回收时将Eden区和Survivor还存活着的对象一次性的拷贝到另一个Survivor区上,最后清理掉Eden区和刚才使用过的Survivor区,Eden和Survivor的默认比例是8:1,可以使用-XX:SurvivorRatio来设置该比例。

而老年代中对象存活率高,没有额外的空间对它进行分配担保,必须使用“标记-清理”或“标记-整理”算法。

内存条abcd分布

java内存区域主要分程序计数器、Java虚拟机栈、本地方法栈、Java堆、方法区、直接内存。其中程序计数器、Java虚拟机栈、本地方法栈属于线程隔离,即他们都有自己的线程归属,其他属于线程共享的。

1、程序计数器。这个是当前线程正在执行的字节码行号指示器。根据这里面的内存数据来确定程序接下来执行的指令。每个线程都有一个,相互隔离,线程切换回来时才知道怎么执行。如果执行的是方法,这里记录的是虚拟机字节码指令的地址。当执行的是Native方法的时候为空(Undefined)。

2、Java虚拟机栈。每个线程私有,里面装的多个栈帧,每个栈帧对于的一个方法。里面存储的是Java方法的内存模型。相当于描述的是一个方法需要的内容。

3、本地方法栈。线程私有,和上一个Java虚拟机栈作用相似,Java虚拟机栈是为Java方法服务,本地方法栈是为Native服务。

4、Java虚拟机管理最大的一块,线程共享,存放对象实例和数组。分新生代(1/3)和老年代(2/3),新生代还可以分Eden(8/10)、FromSurvivor(1/10)、ToSurvivor(1/10),是主要根据垃圾清理来分的。

5、方法区。线程共享,主要存储被虚拟机加载的类信息、常量、静态变量、即时编译器编译后的代码。运行时常量池也是方法区的一部分,比如String有一个常量池,他就是放到这个里面的。

6、直接内存。NIO通过使用Native函数库直接分配对外内存。

Java永久代去哪儿了

Java 8: 从永久代(PermGen)到元空间(Metaspace)

正如大家所知,Java8的新特性之一,是Oracle从JDK7发布以来就一直宣称的要完全移除永久代空间。例如,字符串内部池,已经在JDK7中从永久代中移除。JDK8的发布将宣告它的终结。 PermGen 继任者:Metaspace。

元空间(Metaspace):

一种新的内存空间的诞生

JDK8 HotSpot JVM 使用本地内存来存储类元数据信息并称之为:元空间(Metaspace);这与Oracle JRockit 和IBM JVM’s很相似。这将是一个好消息:意味着不会再有java.lang.OutOfMemoryError: PermGen问题,也不再需要你进行调优及监控内存空间的使用……但请等等,这么说还为时过早。

在默认情况下,这些改变是透明的,接下来我们的展示将使你知道仍然要关注类元数据内存的占用。

请一定要牢记,这个新特性也不能神奇地消除类和类加载器导致的内存泄漏。

你需求使用不同的方法以及遵守新的命名约定来追踪这些问题。

总结如下:

PermGen 空间的状况

这部分内存空间将全部移除。

JVM的参数:PermSize 和 MaxPermSize 会被忽略并给出警告(如果在启用时设置了这两个参数)。

Metaspace 内存分配模型

大部分类元数据都在本地内存中分配。

用于描述类元数据的“klasses”已经被移除。

Metaspace 容量

默认情况下,类元数据只受可用的本地内存限制(容量取决于是32位或是64位操作系统的可用虚拟内存大小)。

新参数(MaxMetaspaceSize)用于限制本地内存分配给类元数据的大小。如果没有指定这个参数,元空间会在运行时根据需要动态调整。

Metaspace 垃圾回收

对于僵死的类及类加载器的垃圾回收将在元数据使用达到“MaxMetaspaceSize”参数的设定值时进行。

适时地监控和调整元空间对于减小垃圾回收频率和减少延时是很有必要的。持续的元空间垃圾回收说明,可能存在类、类加载器导致的内存泄漏或是大小设置不合适。

Java 堆内存的影响

一些杂项数据已经移到Java堆空间中。升级到JDK8之后,会发现Java堆 空间有所增长。

Metaspace 监控

元空间的使用情况可以从HotSpot1.8的详细GC日志输出中得到。

Jstat 和 JVisualVM两个工具,在我们使用b75版本进行测试时,已经更新了,但是还是能看到老的PermGen空间的出现。

前面已经从理论上充分说明,下面让我们通过“泄漏”程序进行新内存空间的观察……

PermGen vs. Metaspace 运行时比较

为了更好地理解Metaspace内存空间的运行时行为,我们建立了一个类元数据泄漏程序。可以从此处下载源代码。

java内存模型,年轻代为什么分为8比1

了解java内存模型对深入了解jvm有很多好处。JMM通过控制主内存与每个线程的本地内存之间的交互,来为开发者提供内存可见性保证。

关于java8内存模型和的介绍到此就结束了,不知道你从中找到你需要的信息了吗 ?如果你还想了解更多这方面的信息,记得收藏关注本站。