一、Java内存模型简介
Java内存模型是Java里面高级技术也是很难理解的部分,希望能通过这篇文章让大家对JMM不在那么陌生,当很了解Java内存模型后Java多线程也就就会变得容易许多。
二、堆、栈和方法区存储了些什么
堆区:
1、存储的全部都是对象,每个对象包含一个与之对应的class的信息。
2、jvm只有一个堆区被所有的线程共享,堆中不存放基本类型和对象的引用
栈区:
1、每个线程包括一个栈区,栈中只保存基本数据类型的对象和自定义对象的引用(不是对象)
2、每个栈中的数据(基本数据类型和对象引用)都是私有的,其他栈没有权限访问
3、栈分为三个区:基本数据类型变量区、执行环境上下文、操作指令区(存放操作指令)
方法区:
1、又叫静态区,跟堆一样,被所有线程共享,包含所有的class对象和静态变量
2、方法区包含的都是整个程序中永远唯一的元素如,static 对象
内存模型图如下:
三、一个类在堆和栈区域如何存储
按照第二点,可以得出一个Employee类在堆、栈、方法区域如何存储的。
如图可以看出,e2和e3在heap区域指向同一个地址,如图所示就是一个类在对喝栈的存储,方法区域存储class信息和静态变量
四、CPU乱序
多线程使用使用和赋值同一个对象时,会导致CPU乱序例如下列代码:
启动10个线程,对静态变量i个自增一万次,每次运行结果都不一样。
首先分析下i++: i++在cpu计算过程中分三步,第一个 获取i的值, 第二步 计算i+1、 第三步赋值 i=新值。
然后分析下CPU乱序:cpu每次都要把计算结果写回到主存中,CPU读写主存相当于一个很慢的IO,需要大量的时间,这时候CPU会将其他运行速度比较快的指定优先运行。
因为cpu乱序和多步计算导致出现结果和预期不一致的问题
为了避免此类问题发送,Java引进了原子类操作类:AtomicInteger,改进后,不在出现循环10万次最终结果不是10万了。
五、Unsafe 原子操作对象
获取Unsafe对象实例:
Unsafe unsafe = (Unsafe) FieldUtils.readStaticField(Unsafe.class, "theUnsafe", true);
Unsafe直接操作数组:
// 获取数组在内存中的位置
long byteBaseOffset = unsafe.arrayBaseOffset(byte[].class);
//定义一个byte数组
byte[] bytes = new byte[10];
//给数组每个元素设置值
for (int x = 0; x < bytes.length; x++) {
unsafe.putByte(bytes, byteBaseOffset + x, (byte) (x+1) );
}
// 获取数组某个元素的值
unsafe.getByte(arg0.bytes, byteBaseOffset + 7 ) ;
六、JVM堆、栈、内存参数设置
-Xms 初始堆大小
-Xmx 最大堆大小
-Xmn 设置年轻代大小
-XX:PermSize 设置持久代(perm gen)初始值
-XX:MaxPermSize 设置持久代最大值
-Xss 每个线程的堆栈大小
-XX:NewRatio 年轻代(包括Eden和两个Survivor区)与年老代的比值(除去持久代)。XX:NewRatio=4 表示年轻代与年老代所占比值为1:4,年轻代占整个堆栈的1/5
-XX:SurvivorRatio Eden区与Survivor区的大小比值。设置为8,则两个Survivor区与一个Eden区的比值为2:8,一个Survivor区占整个年轻代的1/10
-XX:MaxTenuringThreshold 垃圾最大年龄
更多参数,待更新。。。
七、jvm 内存监控
jstat -gcutil 29530 100 10
S0 S1 E O M CCS YGC YGCT FGC FGCT GCT
0.00 99.06 37.01 2.41 96.15 93.00 7 0.368 2 0.426 0.794
0.00 99.06 37.01 2.41 96.15 93.00 7 0.368 2 0.426 0.794
0.00 99.06 37.01 2.41 96.15 93.00 7 0.368 2 0.426 0.794
0.00 99.06 37.01 2.41 96.15 93.00 7 0.368 2 0.426 0.794
0.00 99.06 37.01 2.41 96.15 93.00 7 0.368 2 0.426 0.794
1、S0、S1:Survivor 0/1 使用量(Used)
2、EC、EU:Eden区容量和使用量
3、OC、OU:年老代容量和使用量
4、PC、PU:永久代容量和使用量
5、YGC、YGT:年轻代GC次数和GC耗时
6、FGC、FGCT:Full GC次数和Full GC耗时
7、GCT:GC总耗时
八、持久代被占满
异常:java.lang.OutOfMemoryError: PermGen space
说明: Perm空间被占满。无法为新的class分配存储空间而引发的异常。这个异常以前是没有的,但是在Java反射大量使用的今天这个异常比较常见了。主要原因就是大量动态反射生成的类不断被加载,最终导致Perm区被占满。 更可怕的是,不同的classLoader即便使用了相同的类,但是都会对其进行加载,相当于同一个东西,如果有N个classLoader那么他将会被加载N次。因此,某些情况下,这个问题基本视为无解。当然,存在大量classLoader和大量反射类的情况其实也不多。
解决:
1. -XX:MaxPermSize=1G
2. 换用JDK。比如JRocket。
九、堆栈溢出
异常:java.lang.StackOverflowError
说明:这个就不多说了,一般就是递归没返回,或者循环调用造成
十、线程堆栈满
异常:Fatal: Stack size too small
说明:java中一个线程的空间大小是有限制的。JDK5.0以后这个值是1M。与这个线程相关的数据将会保存在其中。但是当线程空间满了以后,将会出现上面异常。
解决:增加线程栈大小。-Xss512。但这个配置无法解决根本问题,还要看代码部分是否有造成泄漏的部分。
十一、异常:java.lang.OutOfMemoryError: unable to create new native thread
说明:
这个异常是由于操作系统没有足够的资源来产生这个线程造成的。系统创建线程时,除了要在Java堆中分配内存外,操作系统本身也需要分配资源来创建线程。因此,当线程数量大到一定程度以后,堆中或许还有空间,但是操作系统分配不出资源来了,就出现这个异常了。
分配给Java虚拟机的内存愈多,系统剩余的资源就越少,因此,当系统内存固定时,分配给Java虚拟机的内存越多,那么,系统总共能够产生的线程也就越少,两者成反比的关系。同时,可以通过修改-Xss来减少分配给单个线程的空间,也可以增加系统总共内生产的线程数。
解决:
1. 重新设计系统减少线程数量。
2. 线程数量不能减少的情况下,通过-Xss减小单个线程大小。以便能生产更多的线程。
- 大小: 38.8 KB
- 大小: 27.5 KB
- 大小: 42 KB
- 大小: 183.9 KB
分享到:
相关推荐
Java内存模型,简称JMM(Java Memory Model),是Java虚拟机规范中定义的一个抽象概念,它描述了在多线程环境下,如何保证各个线程对共享数据的一致性视图。JMM的主要目标是定义程序中各个变量的访问规则,以及在...
近期,在诚信通开源研究小组的专题学习分享会上,我们针对Java内存模型(JMM)进行了深入探讨,现将JMM相关的一些核心概念进行梳理,以便更好地理解和把握JMM的基本原理。 #### 第一问:JMM是干什么的? JMM (Java ...
Java内存模型(Java Memory Model,JMM)是Java虚拟机(JVM)中的一种内存模型,它描述了程序中各个变量之间的关系,以及在实际计算机系统中将变量存储到内存和从内存中取出变量这样的底层细节。JMM允许编译器和缓存...
Java内存模型(JVM Memory Model,简称JMM)是Java平台中的一个重要概念,它定义了程序中各个变量的访问规则,以及在多线程环境下的内存一致性效果。JMM主要解决的是并发环境下不同线程之间如何共享数据以及如何保证...
Java内存模型,简称JMM(Java Memory Model),是Java编程语言规范的一部分,它定义了程序中各个线程如何访问和修改共享变量,以及如何确保数据的一致性。深入理解Java内存模型对于编写高效的并发程序至关重要。本文...
Java 内存模型(JMM)是Java虚拟机(JVM)规范中的一部分,它旨在确保多线程环境下,程序的正确性和可预测性。JMM处理的主要问题是内存的可见性和一致性,它定义了线程如何与主内存交互以及如何共享变量。 在计算机...
标题和描述中提及的知识点主要围绕Java内存模型(JMM),JVM内存结构,包括堆栈讲解,以及本机内存管理等内容。以下是对这些知识点的详细阐述: ### Java内存模型(JMM) #### JMM简介 Java内存模型(JMM)是Java虚拟机...
Java内存模型(JMM)与JVM内存结构不同,它是针对多线程环境下内存访问的抽象模型。JMM确保在多线程环境下,共享变量的读写操作具有正确的顺序和可见性,通过volatile、synchronized等关键字来实现这一目标。JMM关注...
Java内存模型(JMM)确保了多线程环境下数据的一致性和可见性。主要概念包括主内存、工作内存、 volatile、synchronized和final关键字。volatile能确保变量对所有线程可见,而synchronized则提供了互斥访问,确保...
Java内存模型(JMM)规定了线程对共享变量的可见性和有序性,它通过主内存和工作内存的概念来实现多线程之间的协作。 3. JVM调优:JVM调优通常指对JVM进行配置,优化性能以应对特定的应用需求。常见的调优手段包括...
Java内存模型(JMM)是Java虚拟机规范的一部分,用于定义程序中各个线程对共享变量的访问规则,包括线程之间的通信、内存可见性和原子性等问题。 首先,Java内存模型规定了三个主要区域:程序计数器、虚拟机栈、...
Java内存模型,简称JMM(Java Memory Model),是Java编程语言规范的一部分,它定义了线程如何共享和访问内存,以及在并发编程中如何处理数据一致性的问题。理解JMM对于编写高效、线程安全的Java代码至关重要。 1. ...
Java内存模型(Java Memory Model,简称JMM)是Java虚拟机(JVM)规范中定义的一种内存模型,它涉及了线程之间共享变量的可见性问题。在并发编程中,理解Java内存模型对于编写正确的多线程程序至关重要。 首先,...
Java内存模型(Java Memory Model, JMM)是Java虚拟机(JVM)的一部分,用于规定程序中的各种变量(包括实例字段、静态字段和数组元素等)在多个线程共享内存中的读写行为。JMM的主要目的是确保所有线程能够看到一致...
JSR-133(Java Specification Request 133)则是对JMM的一次重大修订,旨在更精确地定义Java线程和内存模型的行为,以便于开发者更好地理解Java并发机制,并指导JVM实现者设计更高效、符合规范的虚拟机。 #### 锁与...
Java内存模型(Java Memory Model,JMM)是Java虚拟机(JVM)规范中的一个重要组成部分,它定义了程序中各个变量(包括实例域、静态域和数组元素)的访问规则,以及在实际计算机系统中如何将这些变量存储在内存和从...