网站模板为什么不好,百度收录万网空间的网站需要多久,seo 优化技术难度大吗,湛江wx目录
1、引言
1.1 JVM内存与本地内存
1.2 JVM与JDK的关系
2、JVM基础
2.1 JVM#xff08;Java Virtual Machine#xff09;
2.2 Java与JVM的关系
2.3 JVM的内存结构
2.3.1 堆内存
2.3.2 栈内存
2.3.3 方法区
2.3.4 本地方法栈
2.3.5 程序计数器#xff08;PC寄存…目录
1、引言
1.1 JVM内存与本地内存
1.2 JVM与JDK的关系
2、JVM基础
2.1 JVMJava Virtual Machine
2.2 Java与JVM的关系
2.3 JVM的内存结构
2.3.1 堆内存
2.3.2 栈内存
2.3.3 方法区
2.3.4 本地方法栈
2.3.5 程序计数器PC寄存器
2.4 JVM的位置
2.5 JVM的体系结构
2.6 JVM调优
3、类加载器及双亲委派机制
3.1 类加载器的作用
3.2 常见的类加载器
3.3 双亲委派机制
3.4 沙箱安全机制
4、Native方法与JNIJava本地接口
4.1 Native关键字
4.2 JNI的作用
5、程序计数器PC寄存器
5.1 定义
5.2 作用
6、方法区
6.1 定义
6.2 特点
7、Java栈与堆内存
7.1 栈
7.1.1数据结构
7.1.2 线程独立
7.1.3 栈溢出
7.2 堆内存
7.2.1 堆的结构
7.2.2 垃圾回收
7.2.3 堆内存溢出OOM
7.2.4 堆内存的调优
7.2.5 内存分配策略
8、 默认垃圾回收算法
8.1 分代垃圾回收
8.2 垃圾回收器的选择
8.3 总结
9、使用JProfiler工具分析OOM原因
9.1 OOMOutOfMemoryError分析
9.2 工具介绍
9.3 在IDEA中使用JProfiler
10、GC常见的算法
10.1 标记整理标记压缩
10.2 标记清除法
10.3 复制算法
10.4 引用计数器
10.5 GC算法总结
10.6 GC算法与分代收集
11、Java内存模型JMM 1、引言
1.1 JVM内存与本地内存 JVM内存 vs. 本地内存 在JVM中操作时主要是使用JVM虚拟机的内存这包括了堆内存Heap、方法区Method Area、栈内存Stack、本地方法栈Native Method Stack等。JVM负责管理和分配这部分内存。 堆内存用于存储对象实例这是JVM主要使用的内存区域。栈内存用于存储每个线程的局部变量、方法调用链等。方法区用于存储类信息、常量、静态变量等。本地方法栈用于调用本地native方法时使用的内存。JVM操作的这些内存都在其管理之下虽然它运行在操作系统的本地环境中但开发者一般不直接与操作系统的内存打交道。JVM虚拟内存是在操作系统的本地内存之上管理的。简单来说JVM虚拟机的内存是操作系统为它分配的内存的一部分它在此基础上进一步划分和管理。
1.2 JVM与JDK的关系 JVM和JDK的关系 当下载并安装JDKJava Development Kit时JVMJava Virtual Machine就会自动包含在内。JVM是JDK中的一个核心组件它负责执行Java字节码。JDK不仅包含JVM还包括编译器javac、标准类库等开发工具。所以只要你安装了JDKJVM就已经包含在你的环境中了不需要单独下载。
2、JVM基础
2.1 JVMJava Virtual Machine
JVM是Java虚拟机是运行Java程序的基础环境。它负责加载、执行Java字节码并提供内存管理、垃圾回收等功能。Java的跨平台性正是由于JVM的存在因为Java程序在不同操作系统上的JVM上运行从而实现了“写一次处处运行”的特性。
2.2 Java与JVM的关系
Java编译过程Java源代码首先会通过编译器如javac编译成字节码.class文件。这个字节码并不直接运行在物理机器上而是由JVM来解释和执行。JVM的作用JVM是Java程序运行时的核心它接收和解释Java字节码并将其转换为操作系统可执行的机器指令。通过JVMJava程序可以跨平台运行即同一份Java代码可以在不同操作系统上运行。
2.3 JVM的内存结构
官方JVM体系结构图 简易结构图
JVM内存结构分为多个区域每个区域负责管理不同类型的数据和任务
JVM垃圾介绍 堆内存中的垃圾堆中存储所有对象实例由于Java的自动内存管理机制垃圾回收器GC会负责回收不再使用的对象这些未使用的对象即为“垃圾”。方法区中的垃圾虽然方法区存储类信息和常量但在某些情况下未被使用的类或静态数据也会被回收因此方法区本质上也可能产生垃圾。栈内存中的数据Java栈、本地方法栈和程序计数器中存储的是临时数据比如局部变量、方法调用信息等。由于这些区域的生命周期与方法的执行周期相关方法执行完毕后栈帧会自动释放因此不会有垃圾存在。
2.3.1 堆内存
堆Heap用于存储所有Java对象及数组。堆是垃圾回收器GC的主要工作区域因为在这个区域中会产生垃圾对象。
2.3.2 栈内存
Java栈Java Stack存储局部变量、方法调用栈帧等。每个线程都有自己独立的Java栈栈中不会存在垃圾对象因为栈帧随方法执行结束自动释放。
2.3.3 方法区
方法区Method Area存储已加载的类信息、常量、静态变量、即将编译的代码等。方法区本质上是堆内存的一部分但用于特定用途。
2.3.4 本地方法栈
本地方法栈Native Method Stack专门用于调用本地方法使用非Java语言编写的方法如C或C类似于Java栈。
2.3.5 程序计数器PC寄存器
程序计数器PC寄存器存储当前线程执行的字节码的地址程序指令用于跟踪线程的执行进度。
2.4 JVM的位置
JVM运行在操作系统之上充当了Java程序和底层操作系统之间的中间层。JVM实际上是一个软件其主要实现通常是使用C语言编写的部分实现还可能使用其他低级语言如汇编来优化性能。JVM负责屏蔽不同操作系统的细节使Java程序能够在多种平台上运行。
2.5 JVM的体系结构
JVM的体系结构包括多个组成部分主要分为以下几个模块
类加载器系统Class Loader Subsystem负责加载.class文件验证、准备、解析和初始化类。运行时数据区Runtime Data Area包括堆、栈、方法区等用于管理程序执行时的各种数据。执行引擎Execution Engine负责解释执行字节码或将字节码编译为本地机器码。本地方法接口Native Interface用于调用非Java编写的本地方法。垃圾回收系统Garbage Collection System自动管理堆中的对象回收。
2.6 JVM调优
JVM的性能优化通常主要针对堆和方法区进行。因为这两个区域负责管理Java对象、类信息和静态数据并且会产生垃圾。通过调整堆的大小、垃圾回收策略、类加载和卸载等可以提高应用的性能和内存使用效率。
JVM调优的几个常见方面 堆大小设置通过-Xms和-Xmx参数设置堆的初始大小和最大大小。垃圾回收器选择不同的GC算法适合不同的场景如G1适用于大内存应用CMS适用于低延迟应用。方法区调优通过调整方法区的大小和类卸载策略防止内存溢出或类加载过多导致的性能问题。
3、类加载器及双亲委派机制
类加载器及双亲委派机制确保类加载的安全性和有效性通过双亲委派避免核心类被恶意替换。
3.1 类加载器的作用
类加载器ClassLoader负责将.class文件加载到JVM中并转化为内存中的Class对象。具体来说当你创建一个对象如new Student()时类加载器会加载该类的字节码文件而引用对象存放在栈中实际的对象数据存储在堆内存中。
3.2 常见的类加载器
JVM中存在多种类加载器它们按层次结构组织负责加载不同范围的类
虚拟机自带的加载器由JVM内部实现用于加载JDK核心类。启动类加载器Bootstrap ClassLoader又称为根类加载器负责加载JVM核心库通常是$JAVA_HOME/lib中的类如rt.jar。扩展类加载器Extension ClassLoader用于加载扩展库通常是$JAVA_HOME/lib/ext目录下的类。应用程序类加载器Application ClassLoader负责加载用户类路径中的类通常加载classpath中的类是默认的类加载器。
3.3 双亲委派机制
双亲委派机制是一种类加载器的工作方式用来避免类重复加载并保证Java核心类的安全性。
双亲委派机制的执行过程如下
类加载请求当某个类加载器接收到一个类的加载请求时它不会立即尝试加载而是将请求委派给它的父类加载器去处理。逐级向上委派每个类加载器都会将请求向上委托给父类加载器直到最顶层的启动类加载器Bootstrap ClassLoader。启动类加载器检查启动类加载器检查是否能够加载该类如果能则加载并返回否则将请求传递给子类加载器。子类加载器处理如果启动类加载器无法加载才由子类加载器尝试加载。 注意双亲委派机制的一个常见问题是如果我们定义了一个与JDK核心类如java.lang.String同名的类它将永远不会被加载。因为启动类加载器会优先加载java.lang.String类导致我们的自定义类无法加载进而报错如找不到main方法。 通过obj.getClass().getClassLoader()方法可以获取对象的类加载器利用反射可以深入了解类加载器的工作机制。
3.4 沙箱安全机制
沙箱机制是一种保护机制限制程序运行时的系统资源访问防止恶意代码执行或访问敏感资源。类加载器在沙箱机制中扮演了重要角色特别是采用了双亲委派机制防止用户定义的恶意类替代核心类。
沙箱安全机制的组成
字节码校验器确保字节码的正确性和安全性。类加载器采用双亲委派机制防止类加载冲突。存取控制器控制程序对文件、网络等系统资源的访问。安全管理器提供更细粒度的安全策略控制。安全软件包实现Java平台的安全功能如加密、认证等。
4、Native方法与JNIJava本地接口
Native方法与JNI允许Java调用底层代码通过JNI扩展Java的使用范围。
4.1 Native关键字
native关键字用于声明本地方法即用非Java语言如C/C实现的方法。这些方法是因为Java无法直接实现某些底层操作必须调用操作系统或底层库来完成。native方法调用时会进入本地方法栈并通过JNIJava Native InterfaceJava本地接口与底层代码交互。 4.2 JNI的作用
JNI是Java与其他语言如C/C进行交互的桥梁主要作用是扩展Java的能力让Java可以调用非Java的底层代码尤其是在需要高性能或者与系统底层紧密相关的场景下如硬件交互、系统调用等。
5、程序计数器PC寄存器
PC寄存器用于线程的字节码指令跟踪是实现多线程的关键。
5.1 定义
程序计数器Program Counter Register是一个非常小的内存区域每个线程都有一个独立的PC寄存器。它用来存储当前线程正在执行的字节码指令地址指向下一条即将执行的指令。由于Java是多线程的PC寄存器是线程私有的。
5.2 作用
程序计数器用于跟踪线程的执行进度线程切换时通过它恢复到正确的执行位置因此它是实现Java多线程的关键组件之一。
6、方法区
方法区用于存储类信息、静态变量、常量等是JVM内存结构的重要组成部分。
6.1 定义
方法区Method Area是JVM内存的一个逻辑区域它由所有线程共享主要用于存储
已加载的类信息类名、方法、字段等运行时常量池存储编译器生成的常量静态变量类的字节码和方法包括构造方法、接口定义等
6.2 特点
共享区域方法区是线程共享的内存空间不像栈和PC寄存器那样是线程私有的。存储内容主要存储类的元数据、静态变量、常量池等而对象实例是存储在堆中的。垃圾回收尽管方法区存储静态信息但在某些情况下如类卸载也会触发垃圾回收。
7、Java栈与堆内存
7.1 栈
7.1.1数据结构
数据结构栈是一种后进先出LIFOLast In First Out的数据结构只有栈顶的元素可以被访问和修改。
7.1.2 线程独立
线程独立每个线程都有自己的栈栈的生命周期与线程相同。栈内存内容 八大基本数据类型如int, char等对象引用指向堆中实际对象的引用方法调用每当一个方法被调用时相关信息如局部变量、参数等会存放在栈中。
7.1.3 栈溢出 栈溢出 栈溢出Stack Overflow通常发生在递归调用中如果方法循环调用而没有终止条件最终会耗尽栈空间导致溢出错误。
7.2 堆内存 堆内存 单一堆一个JVM实例只有一个堆内存所有线程共享这个堆。堆内存的调节可以通过JVM参数进行配置通常会调整堆的初始大小和最大大小。 JVM实现 三种常见的JVM实现 Sun公司的HotSpotBEA的JRockitIBM的J9 VM 注意从JDK 1.8开始永久代PermGen被移除改为使用元空间Metaspace来存储类的元数据。
7.2.1 堆的结构 堆的结构 堆内存通常被细分为几个区域 新生区Eden Space 对象在此区域被创建使用new关键字。如果新生区满了会触发轻量级垃圾回收轻GC。幸存者区Survivor Space分为S0和S1 新生区经过一次GC后存活的对象会被转移到这里。经过几次GC后仍然存活的对象可能被转移到老年代。老年区Old Generation 存放长时间存活的对象通常是经历过多次GC的对象。元空间Metaspace 存放类的元数据从JDK 1.8开始取代永久代。元空间使用本地内存物理上不存在限制。 图
7.2.2 垃圾回收
垃圾回收 轻量级垃圾回收轻GC主要针对新生区的对象。重量级垃圾回收重GC通常针对老年区的对象处理复杂和耗时。
7.2.3 堆内存溢出OOM
堆内存溢出OOM 当堆内存不足以满足对象创建需求时会抛出OutOfMemoryErrorOOM。 常见原因包括创建过多的对象尤其是字符串等长生命周期的对象。 图 字符串处理 在Java中字符串的长度是动态的但受限于可用内存。大量字符串或过长字符串会导致堆内存溢出。
7.2.4 堆内存的调优
堆内存的调优 新生区调优设置合适的大小以优化轻GC的频率和效率。老年区调优通过调整老年区大小来减少重GC的次数
7.2.5 内存分配策略
JVM默认情况下分配的总内存通常是计算机内存的1/4而初始化内存是1/64。可以通过命令行参数调整这些值。默认分配值idea代码 public static void main(String[] args) {long max Runtime.getRuntime().maxMemory();long total Runtime.getRuntime().totalMemory();System.out.println(max max 字节\t (max / (double) 1024 / 1024) MB);System.out.println(total total 字节\t (total / (double) 1024 / 1024) MB);} IDEA中进行JVM调参参数调优JVM调优就是在这边地方调优。调优区别原本241MB内存大小调成了981MB 参考原始参数下图是调优后的参数。避免堆内存OOM错误 调优参数 -Xms1024m -Xmx1024m -XX:PrintGCDetails 控制台中新生区伊甸园、老年区、元空间
总结 栈用于存储方法调用和局部变量每个线程都有独立的栈。堆用于存储对象所有线程共享一个堆内存分为新生区、幸存者区、老年区和元空间。垃圾回收的策略影响对象的生存周期与内存使用效率。堆内存的调优对于大型应用性能至关重要合理配置内存可以有效防止OOM错误。
在 Java 中垃圾回收器GCGarbage Collector主要负责自动管理内存的分配和释放。Java 虚拟机JVM中的垃圾回收机制是基于 分代回收 理念的这种机制认为对象的生命周期是不一样的因此可以根据对象存活的时间长短采用不同的回收策略。
8、 默认垃圾回收算法
Java 的垃圾回收器默认使用 HotSpot VM它采用的垃圾回收算法是 分代垃圾回收算法Generational Garbage Collection结合了多种不同的垃圾回收算法具体包括
新生代回收算法复制算法Copying Algorithm老年代回收算法标记-清除算法Mark-Sweep Algorithm和 标记-整理算法Mark-Compact Algorithm
8.1 分代垃圾回收 新生代大多数新创建的对象会被分配在新生代。新生代中的对象大部分都是“朝生夕死”的因此新生代的垃圾回收主要使用 复制算法将存活对象从一个区域复制到另一个区域非存活对象则直接被清理。 Eden 区新对象首先分配在 Eden 区。Survivor 区对象在 Eden 区中经过一次垃圾回收后如果没有被清理会被移动到 Survivor 区。算法 新生代中主要使用 复制算法Copying Algorithm它将存活的对象复制到另一个区域而非存活的对象则会被回收。这种方法回收速度很快因为它不需要遍历所有对象只需处理存活的对象。 老年代新生代中经过多次垃圾回收后仍然存活的对象会被晋升到老年代。老年代中的对象通常存活时间较长因此回收频率较低。 算法 标记-清除算法Mark-Sweep Algorithm先标记出所有存活的对象然后清理掉未标记的对象。缺点是容易产生内存碎片。标记-整理算法Mark-Compact Algorithm在标记完存活对象后不仅清理掉未存活的对象还会将存活对象整理到一起避免内存碎片问题。
8.2 垃圾回收器的选择
虽然 Java 默认使用的是分代回收机制但具体使用的垃圾回收器可以根据 JVM 的配置不同而变化以下是常见的几种垃圾回收器
Serial GC一个简单的单线程垃圾回收器适合单核 CPU 和小型应用。Parallel GC多线程垃圾回收器适合多核 CPU 和注重吞吐量的应用。G1 GC一种面向服务端应用的垃圾回收器旨在减少 GC 造成的停顿时间替代了老年代的 CMSConcurrent Mark-Sweep回收器。ZGC 和 Shenandoah GC专注于极低停顿时间的垃圾回收器适用于超低延迟应用。
8.3 总结
Java 默认采用的是基于 分代垃圾回收算法 的策略其中新生代主要使用 复制算法而老年代结合 标记-清除 和 标记-整理 算法。这种分代回收机制优化了内存管理使得不同生命周期的对象能被高效回收。
9、使用JProfiler工具分析OOM原因
9.1 OOMOutOfMemoryError分析
OOMOutOfMemoryError分析 内存快照分析使用内存快照工具如JProfiler、MAT可以方便地查看在OOM发生时的内存状态定位具体出错的代码行。代码行定位通过内存快照分析可以快速找到导致内存泄漏或堆溢出的代码位置避免逐行调试的麻烦。
9.2 工具介绍
工具介绍 MATMemory Analyzer Tool用于分析Java堆转储文件帮助定位内存泄漏、获取堆中对象的数据、找到占用内存大的对象等。JProfiler强大的性能分析工具能够监控应用的内存使用情况生成内存快照并分析内存泄漏。实时监控
9.3 在IDEA中使用JProfiler
插件安装在IDEA中安装JProfiler插件可以集成性能分析和监控功能。JProfiler官网上下载 官网ej-technologies - JProfiler编写OOM异常代码 在IDEA中编写可能导致OOM的代码利用JProfiler监控具体行数 public class OOMExample {public static void main(String[] args) {ListString list new ArrayList();while (true) {list.add(This is a very long string that will keep consuming memory...);}}
} 调参 -Xms1m -Xmx8m -XX:HeapDumpOnOutOfMemoryError -Xms设置JVM的初始内存分配大小建议设置为总内存的1/64例如-Xms512m。 -Xmx设置JVM的最大内存分配大小建议设置为总内存的1/4例如-Xmx2048m。 -XX:PrintGCDetails打印垃圾回收的详细信息帮助分析内存使用情况和垃圾回收的效果。 监控软件使用 配置 -XX:HeapDumpOnOutOfMemoryError -XX:HeapDumpPathC:\Users\Sachsen\Desktop\testKZ -Xms512m -Xmx512m 代码 public static void main(String[] args) {String str zhangSan;while (true) {str str new Random().nextInt(1888888888) new Random().nextInt(999999999);}} java.lang.OutOfMemoryError 配置的文件目录下生成快照查看当前对象集查看栈溢出的对象第一种方式Current Object Set对象集传递引用查看查看栈溢出的对象第二种方式Current Object Set对象集图像结构查看查看栈溢出的对象查看的第三种方式Thread Dump线程转储查看 线程转储记录了快照时的所有线程可以查看线程运行状态运行、等待、阻塞等和线程调用栈展现线程执行的方法调用路径。运行出现错误的线程会用一个特殊的图标标记。
总结 使用JProfiler和MAT等工具可以快速定位和分析OOM的原因减少线下调试的时间。合理配置JVM内存参数有助于防止内存溢出。对于GC的了解能够帮助优化应用的内存使用和性能。
10、GC常见的算法 10.1 标记整理标记压缩
概念首先标记活着的对象然后将它们整理到内存的一端释放出连续的空闲空间。优点减少了内存碎片使内存使用更高效。缺点需要额外的时间来移动对象。
10.2 标记清除法
概念标记所有活着的对象然后直接清除未标记的对象。优点实现简单不需要额外空间。缺点存在内存碎片可能导致内存浪费。
10.3 复制算法
概念将存活的对象从Eden区复制到两个幸存者区中的一个To区当进行垃圾回收时清空Eden区。工作过程 Eden区每次GC时将Eden区的存活对象复制到幸存者区的To区。养老区对象经历一定次数的GC默认15次后若仍存活则被转移到老年区。优点内存利用率高适合存活时间较短的对象。缺点Eden和幸存者区可能会产生空闲区域浪费内存。
10.4 引用计数器
概念为每个对象维护一个计数器记录引用该对象的数量。当计数器为0时自动回收对象。优点简单易实现。缺点无法处理循环引用效率低不推荐使用。
10.5 GC算法总结
内存效率复制算法标记清除算法标记压缩算法时间复杂度
内存整齐度复制算法标记压缩算法标记清除算法
内存利用率标记压缩算法标记清除算法复制算法
10.6 GC算法与分代收集
GC算法通过不同的策略管理内存优化性能与资源利用。GC算法也称为分代收集算法因为它利用了对象生命周期的特性将对象分为新生代Eden和幸存者区和老年区。
11、Java内存模型JMM
JMM确保多线程编程中内存访问的一致性和安全性。定义Java内存模型规定了Java程序中线程如何访问共享内存确保线程间的可见性与一致性。主要内容 主内存与工作内存JMM将内存划分为主内存共享内存和工作内存线程的私有内存。内存屏障确保特定的操作顺序和内存可见性。可见性确保一个线程对共享变量的修改能被其他线程看到。原子性保证对共享变量的操作是不可分割的。