网站建站网站建站,开发公司网签补充合同,wordpress文章封面,网站做app的好处针对java项目做性能测试的时候#xff0c;很多同学都见过一个报错#xff0c;就是OOM【Out Of MemoryError】#xff1b;那出现这种报错就是项目发生了内存溢出的问题#xff0c;这是比较严重的性能问题。所以#xff0c;作为一个性能测试工程师#xff0c;我们要能够分析…针对java项目做性能测试的时候很多同学都见过一个报错就是OOM【Out Of MemoryError】那出现这种报错就是项目发生了内存溢出的问题这是比较严重的性能问题。所以作为一个性能测试工程师我们要能够分析JVM内存的问题以及理解其中的原理才能更好的给JVM内存出现的性能瓶颈问题进行调优。JVM概念要学习JVM内存问题分析和调优之前我们先来了解一下什么是JVMJVM【java virtual machine】: java虚拟机是Java程序运行所需要的一台虚拟机器。在操作系统上运行一个java程序的过程中也就是通过“java -jar ” 启动一个java进程的同时就会启动一个java虚拟机。java虚拟机是在操作系统之上的程序JVM直接和操作系统进行交互不跟硬件直接交互。但是java虚拟机可以管理自己的进程和线程有自己独立的内存管理自己的内存这个叫做JVM内存。JVM的优点可以实现一次编写到处运行 并支持一个包在Linux和windows mac等不同的平台都可以直接兼容运行有自动内存管理和垃圾回收机制这是JVM非常重要的一个关键特性这个机制叫做GC 【Garbage Collection】代码写完对象不需要开发人员手动释放内存而是自动回收内存这是java应用程序的JVM内存的独有机制 相比于其他的语言 C是不存在自动回收的需要手动删除。覆盖广因为现在市面上java语言的项目很多很普遍所以只要是java项目都是基于jvm实现的。JVM内存模型现在的java程序都是基于1.8版本因为java1.8是目前稳定主流的版本企业基本都兼容1.8及其以上的版本所以我们学习1.8java版本的内存模型就可以了。注意不同版本之间JVM内存存在一定差异比如只有1.8的版本及之后才有元空间的概念之前的jvm没有元空间。jvm运行时有5块数据区分别如下程序计数器线程私有虚拟机栈线程私有本地方法栈线程私有方法区线程共享五个部分分别来详细介绍一下1、程序计数器线程私有用于存储指向下一条指令的地址是一块很小的空间一般不会有内存问题也不会进行垃圾回收。所以做性能测试的时候我们不太需要关注。作用用于存储指向下一条指令的地址特点很小的内存区域读取速度很快每个线程独有线程之间不会相互干扰JVM中唯一一个没有Out Of Memory Error的区域也没有用到垃圾回收2、虚拟机栈线程私有随着线程创建而创建随着线程消失而销毁。作用每个线程在创建时都会创建一个虚拟机栈所以线程独有其内部保存一个个的栈帧Stack Frame对应着一次次的Java方法调用这个线程每次调用方法、调用函数等都会进行一个栈帧的入栈调用的方法函数越多嵌套越深栈帧就会越多方法执行完了就会把栈帧丢出去叫做出栈特点线程独有JVM对虚拟机栈的两个操作方法执行—进栈方法结束—出栈。栈并不存在垃圾回收的概念因为方法调用完成栈帧就丢出去了不需要jvm控制垃圾回收但是可能会存在栈溢出。• 如果栈帧的数量过多不停的入栈超过了虚拟机栈的容量或者某些栈帧过大会引发栈溢出SOE(StackOverflowError) 比如代码出现死循环等。• 如果某些方法的参数或者返回值结果等太大 会导致栈帧过大超过了虚拟机栈的容量也会出现栈溢出。3、本地方法栈与虚拟机栈类似是线程私有的 发生性能问题的概率很低所以不需要太多关注。4、方法区【元空间】是线程共享的共享的意思就是随着程序的启动而启动除非进程关掉才会消失不会因为线程而消失。比如一个方法里比如有10个线程共享方法区里面的类、常量、静态变量等信息不会每个线程启动单独开辟一个空间给它而是大家共享这个方法区。在java1.8版本里方法区就是元空间在1.7版本叫做永久代。不过现在主流都是1.8版本所以我们就了解元空间即可。元空间用来保存程序被编译完成后被虚拟机加载到内存的一些 类信息、常量、静态变量以及即时编译器编译后的代码等数据一般是一些不怎么会篡改和变动的数据会存在元空间。所以程序启动后元空间的大小基本不会变化。元空间的大小可以通过参数进行配置如果我要存的类信息、常量、静态变量信息很多超过分配的元空间的大小就可能导致 内存溢出抛出错误OutOfMemoryError 。**5、堆**这是线程共享的 jvm内存最大最重要的区域性能问题出现比较多的地方一定要重点掌握。在虚拟机启动时创建java -jar命令启动程序后内存大小就分配好了。存放对象实例几乎所有的对象实例都在这里分配内存 ; 比如代码里new 一个对象会存在这里new的对象越多 就会存在内存越多。当堆中没有内存分配给对象实例时会抛出内存溢出的报错信息OutOfMemoryError 。堆里划分为新生代、老年代 注意java1.8版本里只有这两个没有永久代了新生代用于存储一些存储时间短的对象主要包括三个部分1Eden: 叫做伊甸区 用于存放JVM刚分配的对象数据2From Survivor【存活1区】3To Survivor【存活2区】• 存活1区和存活2区两个空间一样大Eden中未被GC【垃圾回收】的对象会在这两个区间来回copy默认拷贝超过15次还没有被GC的对象就被移入年老代 。老年代大对象或者多次被GC后还存在的对象就会存到老年代它的空间比新生代大很多在老年代快满的时候会触发一次FGCFGC是需要很长时间的触发一次的full GC发生的时候老年代和年轻代都会发生一次GC当新生代和老年代都占满了GC也释放不出来更多内存了如果此时还在产生一些新的对象那么就会发生内存溢出【OOM】的错误如下图所示JVM的参数设置了解了JVM的组成部分那么在启动项目的时候为了调整性能我们就可以针对JVM内存的大小的设置和调整来优化项目的性能。常见的参数有如何设置这些参数呢我们来结合项目实际案例给大家讲解这些参数的设置1、启动某JAVA项目进程ps -ef 查看java进程id2、使用jmap -heap 1727 命令查看这个java进程的 jvm的内存设置这些是在代码里写好的默认初始值3、还可以看到堆内存的使用情况4、如果要修改和调整这些大小就可以去修改项目的配置文件。比如如果你们的是基于tomcat的那么可以修改catalina.bat 或者 catalina.sh 配置文件来调整这些参数的大小如下图在配置文件里加一行设置参数大小并保存文件5、配置完成后重新shutdown tomcat的服务 再次启动这个服务查看一下启动的进程ps -ef | grep java 可以看到启动进程的命令里参数配置成功了常见JVM内存的面试题1、JVM里哪些内存会被回收【GC】1是否已死使用的是是引用计数算法被引用的计数等于0时会被回收。注意引用计数为0 会放在这个堆里只有发生了GC的时候会检测到计数为0 才会回收不会计数为0 立马被回收了。2可达性算法没有引用链的对象内存会被回收这个会出现频率高一些链表里存储谁调用了这个对象信息就是引用链指向这个被引用者。每个对象维护一个引用链。如果引用链指向着为空了说明没有人调用这个对象那么就可以被回收了。2、JVM内存会在什么时候被回收有两种场景会触发GC操作1分配的JVM内存空间不足的时候才会执行回收2也可以设置定时回收。感谢每一个认真阅读我文章的人礼尚往来总是要有的虽然不是什么很值钱的东西如果你用得到的话可以直接拿走这些资料对于【软件测试】的朋友来说应该是最全面最完整的备战仓库这个仓库也陪伴上万个测试工程师们走过最艰难的路程希望也能帮助到你!有需要的小伙伴可以点击下方小卡片领取