Java基础之《JVM性能调优(3)—堆》
一、什么是堆,它和栈有什么区别?
1、变量和堆的关系
package heap;public class Test01 {public static void test() {int j = 100;}public static void main(String[] args) {int i = 10;test();}
}
以上代码的执行顺序:
(1)main方法,java虚拟机栈开辟了一个栈帧,存放变量int i = 10
(2)执行到test方法时,java虚拟机栈新开辟一个栈帧,存放变量int j = 100
(3)test方法执行完后,test栈帧被回收(后进先出),但是main栈帧没执行完就没回收
方法的变量和堆没有关系,存储在栈帧里
2、数组和堆的关系
package heap;public class Test02 {public static void main(String[] args) {int[] x = new int[5];x[0] = 100;x = null;}
}
以上代码的执行顺序:
(1)执行main方法,java虚拟机栈开辟了一个栈帧。
当执行int[] x = new int[5]时,栈开辟了x变量空间,该变量存放的是堆的引用地址。
堆开辟了x数组空间,例如0x0001,存放数组的值。数组的元素都设置默认值0.
栈里的x存放的是堆的引用地址,例如x = 0x0001。
(2)执行x[0]=100时,
堆会为x[0]=100,栈的x变量不会变,继续引用堆的地址。
(3)当执行x=null时,x引用的内存地址被删除,例如栈帧删除了0x0001。而堆中的数组不再被x使用后,就会变成垃圾,堆不会立即删除,它是采用垃圾回收算法删除。
package heap;public class Test03 {public static void main(String[] args) {int[] x = new int[5];x[0] = 100;int y[] = x;x = null;}
}
以上代码:
(4)当执行了int[] y = x时,栈开辟了y变量空间,该变量存放的是堆的引用地址0x0001。即y和x一样都是引用同一个地址。
当执行x=null时,x引用的内存地址被删除。但堆中的0x0001仍然被y引用,堆中的数据会一直存在,不会被垃圾回收算法删除。
3、对象和堆的关系
package heap;public class Test04 {public static void main(String[] args) {Book book1 = new Book("java", "aaa");Book book2 = new Book("jvm", "bbb");}public static class Book {private String name;private String author;public Book(String name, String author) {this.name = name;this.author = author;}public String getName() {return name;}public void setName(String name) {this.name = name;}public String getAuthor() {return author;}public void setAuthor(String author) {this.author = author;}}
}
以上代码:
定义了2个对象,栈开辟了2个空间存放堆的地址,堆开辟了2个空间存储数据。
只要每次new一个对象,堆都会为对象分配空间存储。
4、总结
栈:
(1)基本数据类型、局部变量存放在栈帧内,方法执行完毕(栈帧出栈)立即释放,节约空间。
(2)栈帧内的变量,没有默认值,需要手工设置。(方法里的变量是没有默认值)
(3)栈帧只存留在单个线程中,其他线程访问不了。
(4)可以使用-Xss来定义栈内存大小。
(5)当堆栈内存已满时,Java运行时抛出java.lang.StackOverFlowError
堆:
(1)数组和对象存于堆中,用完后(栈帧不再引用),靠垃圾回收算法清除。
(2)堆内对象的变量都有默认值。
(3)所有的线程共享堆,即所有栈帧的变量都能引用堆的内存地址。
(4)可以使用-Xms和-Xmx的JVM选项来定义堆内存的启动大小和最大大小。
(5)如果堆内存已满,则抛出java.lang.OutOfMemoryError
二、什么是短命对象,什么是长命对象
package heap;import java.util.ArrayList;
import java.util.List;public class Father {private List<Son> sons = new ArrayList<Son>();public Son giveSon(String name) {return new Son(name);}public static void main(String[] args) {Father father = new Father();Son a = father.giveSon("a");father.sons.add(a);father.giveSon("b");}
}
1、长命对象
一直有人引用就是长命对象
(1)栈一直引用,例如main函数一直运行,它的对象father就一直存活。
(2)栈帧出栈后,对象被其他对象引用,例如giveSon("a"),出栈后被sons引用。
2、短命对象
没人引用就是短命对象,也称为垃圾对象,因为没人用它,即没人引用它,例如giveSon("b")出栈后里面的son没人引用,就变成垃圾了。
3、在JVM中,大部分都是短命对象;少数对象长期存活,例如main函数的栈一直引用father,Father的sons一直引用son a。
三、为什么要设计分代模型:年轻代和老年代
1、什么是分代模型
分代模型:把堆分为年轻代、老年代
年轻代:存储短命对象
老年代:存储长命对象
2、为什么要这么设计
因为来源于生活,例如:
生活垃圾放在垃圾桶(年轻代),因为生活垃圾对你没用,所以拿个垃圾桶存起来。
钻石黄金存放到保险柜(老年代),因为钻石黄金对太多人有用了,所以拿个保险柜保存起来。
如果不设计分代,那钻石黄金和生活垃圾就放在一起了,乱套了。
四、基于参数设置jvm内存空间
1、如何查看当前堆的大小
package heap;import com.sun.management.OperatingSystemMXBean;
import java.lang.management.ManagementFactory;public class TestB01 {public static void main(String[] args) {int byteToMb = 1024 * 1024;long totalMemory = Runtime.getRuntime().totalMemory() / byteToMb;long maxMemory = Runtime.getRuntime().maxMemory() / byteToMb;System.out.println("当前初始内存大小 -Xms :" + totalMemory + "MB");System.out.println("当前最大内存大小 -Xmx :" + maxMemory + "MB");//操作系统级内存情况查询OperatingSystemMXBean osmxb = (OperatingSystemMXBean) ManagementFactory.getOperatingSystemMXBean();long physicalFree = osmxb.getFreePhysicalMemorySize() / byteToMb;long physicalTotal = osmxb.getTotalPhysicalMemorySize() / byteToMb;long physicalUse = physicalTotal - physicalFree;System.out.println("操作系统物理内存已用空间:" + physicalUse + "MB");System.out.println("操作系统物理内存空闲空间:" + physicalFree + "MB");System.out.println("操作系统总物理内存大小:" + physicalTotal + "MB");System.out.println("默认堆 初始内存大小:物理电脑内存大小 / 64 = " + physicalTotal / 64 + "MB");System.out.println("默认堆 最大内存大小:物理电脑内存大小 / 4 = " + physicalTotal /4 + "MB");}
}
2、通过参数,自定义堆内存大小
堆的大小在jvm启动时就已经设定好了,可以通过“-Xms”和“-Xmx”来进行设置:
(1)-X是jvm的运行参数
(2)“-Xms”用于表示堆区的起始内存,ms是memory start
(3)“-Xmx”用于表示堆区的最大内存,比如手动设置:-Xms512m -Xmx512m
五、基于jmap剖析堆的内部结构
1、jmap命令
jmap命令是一个可以输出所有内存中对象的工具,甚至可以将VM中的heap,以二进制输出成文本。
打印出某个java进程(使用pid)内存内的,所有“对象”的情况(如:产生那些对象,及其数量)。
2、采用springboot来试验
jmap -heap 32594
Attaching to process ID 32594, please wait...
Debugger attached successfully.
Server compiler detected.
JVM version is 25.231-b11using thread-local object allocation.
Parallel GC with 2 thread(s)Heap Configuration:MinHeapFreeRatio = 0MaxHeapFreeRatio = 100MaxHeapSize = 1073741824 (1024.0MB)NewSize = 357564416 (341.0MB)MaxNewSize = 357564416 (341.0MB)OldSize = 716177408 (683.0MB)NewRatio = 2SurvivorRatio = 8MetaspaceSize = 21807104 (20.796875MB)CompressedClassSpaceSize = 1073741824 (1024.0MB)MaxMetaspaceSize = 17592186044415 MBG1HeapRegionSize = 0 (0.0MB)Heap Usage:
PS Young Generation
Eden Space:capacity = 290455552 (277.0MB)used = 44679448 (42.609642028808594MB)free = 245776104 (234.3903579711914MB)15.382542248667363% used
From Space:capacity = 33030144 (31.5MB)used = 4053248 (3.865478515625MB)free = 28976896 (27.634521484375MB)12.271360367063492% used
To Space:capacity = 33554432 (32.0MB)used = 0 (0.0MB)free = 33554432 (32.0MB)0.0% used
PS Old Generationcapacity = 716177408 (683.0MB)used = 43105960 (41.109046936035156MB)free = 673071448 (641.8909530639648MB)6.01889413411935% used32413 interned Strings occupying 3173232 bytes.
Parallel GC with 2 thread(s):采用并行垃圾收集器
MinHeapFreeRatio:JVM最小空闲比率,可由-XX:MinHeapFreeRatio=<n>参数设置,jvm heap 在使用率小于n时,heap进行收缩
MaxHeapFreeRatio:JVM最大空闲比率,可由-XX:MaxHeapFreeRatio=<n>参数设置,jvm heap 在使用率大于n时,heap进行扩张
MaxHeapSize:JVM堆的最大大小,可由-XX:MaxHeapSize=<n>参数设置
NewSize:JVM新生代的默认大小,可由-XX:NewSize=<n>参数设置
MaxNewSize:JVM新生代的最大大小,可由-XX:MaxNewSize=<n>参数设置
OldSize:JVM老生代的默认大小,可由-XX:OldSize=<n>参数设置
NewRatio:新生代:老生代(的大小)= 1:2,可由-XX:NewRatio=<n>参数指定New Generation与Old Generation heap size的比例
SurvivorRatio:survivor:eden = 1:8,即survivor space是新生代大小的1/(8+2),[因为有两个survivor区域],可由-XX:SurvivorRatio=<n>参数设置
PS:survivor和eden是新生代里面的东西
MetaspaceSize:元空间的默认大小,超过此值就会触发Full GC,可由-XX:MetaspaceSize=<n>参数设置
CompressedClassSpaceSize:类指针压缩空间的默认大小,可由-XX:CompressedClassSpaceSize=<n>参数设置
MaxMetaspaceSize:元空间的最大大小,可由-XX:MaxMetaspaceSize=<n>参数设置
G1HeapRegionSize:使用G1垃圾收集器的时候,堆被分割的大小,可由-XX:G1HeapRegionSize=<n>参数设置
PS Young Generation:新生代内存分布,包含eden区和survivor区
Eden Space:eden区内存
From Space:survivor区的from内存
To Space:survivor区的to内存
PS Old Generation:老生代区内存
3、堆的大小
4、总结
(1)java的堆是按照垃圾收集器来设计的。目前主流的垃圾收集器G1,分代设计的垃圾收集器主要是CMS、G1。
(2)堆的分代设计,就是把一块内存划分为多块。
(3)堆的内存空间分配主要是分为2块,年轻代和老年代。
(4)年轻代和老年代的比例是1:2,可采用-X:NewRatio=<n>来调节设置。
(5)年轻代分为Eden和Survivor From、Survivor To的大小比例是8:1:1,可采用-XX:SurvivorRatio=<n>来调节设置。
六、如何读懂gc日志
1、参数说明
-Xms30M -Xmx30M:年轻代10M,老年代20M
-XX:+PrintGCDetails(jdk11废弃,换成-Xlog:gc*):输出GC的详细日志
-XX:+PrintHeapAtGC(jdk11废弃,换成-Xlog:gc+heap=trace):打印出触发GC之前、之后的日志
package heap;public class GcTest01 {private static final int _1MB = 1024 * 1024;/**-Xms30M-Xmx30M-XX:+PrintGCDetails(jdk11废弃,换成-Xlog:gc*)-XX:+PrintHeapAtGC(jdk11废弃,换成-Xlog:gc+heap=trace)*/public static void main(String[] args) throws InterruptedException {byte[] allocation, allocation2, allocation3, allocation4;allocation = new byte[8*_1MB];System.out.println("----------创建8M后----------");allocation2 = new byte[8*_1MB];System.out.println("----------创建8M后----------");allocation3 = new byte[8*_1MB];System.out.println("----------创建8M后----------");}
}
执行结果:
----------创建8M后----------
----------创建8M后----------
{Heap before GC invocations=1 (full 0):PSYoungGen total 9216K, used 2023K [0x00000000ff600000, 0x0000000100000000, 0x0000000100000000)eden space 8192K, 24% used [0x00000000ff600000,0x00000000ff7f9d30,0x00000000ffe00000)from space 1024K, 0% used [0x00000000fff00000,0x00000000fff00000,0x0000000100000000)to space 1024K, 0% used [0x00000000ffe00000,0x00000000ffe00000,0x00000000fff00000)ParOldGen total 20480K, used 16384K [0x00000000fe200000, 0x00000000ff600000, 0x00000000ff600000)object space 20480K, 80% used [0x00000000fe200000,0x00000000ff200020,0x00000000ff600000)Metaspace used 3297K, capacity 4496K, committed 4864K, reserved 1056768Kclass space used 358K, capacity 388K, committed 512K, reserved 1048576K
[GC (Allocation Failure) [PSYoungGen: 2023K->840K(9216K)] 18407K->17232K(29696K), 0.0005962 secs] [Times: user=0.00 sys=0.00, real=0.00 secs]
Heap after GC invocations=1 (full 0):PSYoungGen total 9216K, used 840K [0x00000000ff600000, 0x0000000100000000, 0x0000000100000000)eden space 8192K, 0% used [0x00000000ff600000,0x00000000ff600000,0x00000000ffe00000)from space 1024K, 82% used [0x00000000ffe00000,0x00000000ffed2020,0x00000000fff00000)to space 1024K, 0% used [0x00000000fff00000,0x00000000fff00000,0x0000000100000000)ParOldGen total 20480K, used 16392K [0x00000000fe200000, 0x00000000ff600000, 0x00000000ff600000)object space 20480K, 80% used [0x00000000fe200000,0x00000000ff202020,0x00000000ff600000)Metaspace used 3297K, capacity 4496K, committed 4864K, reserved 1056768Kclass space used 358K, capacity 388K, committed 512K, reserved 1048576K
}
......
2、触发了Young GC
[GC (Allocation Failure) [PSYoungGen: 2023K->840K(9216K)] 18407K->17232K(29696K), 0.0005962 secs] [Times: user=0.00 sys=0.00, real=0.00 secs]
说明:
(1)GC (Allocation Failure):对象分配失败,此时就要触发一次Young GC
年轻代(Eden区和From区)内存不足,所以触发了Young GC
(2)PSYoungGen: 2023K->840K(9216K):
(9216K):年轻代可用空间是9216KB,也就是9MB。Eden区是8M,两个Survivor中只有一个是可以放存活对象的,另外一个是必须一直保持空闲的,所以它考虑年轻代的可用空间,就是1个Eden + 1个Survivor - from的大小,也就是9MB。
2023K->840K:意思是对年轻代执行了一次GC,GC之前都使用了2023KB了,但是GC之后只有840KB的对象是存活下来
(3)18407K->17232K(29696K)
18407K:GC前堆内存占用
17232K:GC后堆内存占用
29696K:堆内存总量
(4)0.0005962 secs
这个就是本次gc耗费的时间,大概耗费了0.6ms,仅仅是回收1.2MB的对象而已。
3、触发了GC前后
从执行结果看出,触发前内存占用Eden区。触发垃圾回收后,Eden区清空,From区填满了,老年代也使用了。
Heap after GC invocations=1 (full 0):PSYoungGen total 9216K, used 840K [0x00000000ff600000, 0x0000000100000000, 0x0000000100000000)eden space 8192K, 0% used [0x00000000ff600000,0x00000000ff600000,0x00000000ffe00000)from space 1024K, 82% used [0x00000000ffe00000,0x00000000ffed2020,0x00000000fff00000)to space 1024K, 0% used [0x00000000fff00000,0x00000000fff00000,0x0000000100000000)ParOldGen total 20480K, used 16392K [0x00000000fe200000, 0x00000000ff600000, 0x00000000ff600000)object space 20480K, 80% used [0x00000000fe200000,0x00000000ff202020,0x00000000ff600000)Metaspace used 3297K, capacity 4496K, committed 4864K, reserved 1056768Kclass space used 358K, capacity 388K, committed 512K, reserved 1048576K
说明:
(1)PSYoungGen中最前面的PS代表垃圾收集器是Parallel垃圾收集器,回收的区域是新生代YoungGen。
(2)ParOldGen中最前面的Par代表垃圾收集器是Parallel Old收集器,回收的区域是老年代OldGen。
(3)Metaspace是元数据空间和Class空间,存放一些类信息、常量池这类的东西。
七、为什么内存看似够但触发了young gc
因为在启动jvm的时候,jvm自身自带了初始化对象占用了空间。
JVM启动的时候,就必须占用了3351K,3351K是系统自带的。
package heap;public class GcTest02 {public static void jp(String[] args) throws InterruptedException {Thread.sleep(1000000000);}
}
1、3351K是什么对象?
采用jmap -histo:live命令来查看
说明:
histo:live代表查看当前jvm存活的对象
jmap -histo:live 20504
num #instances #bytes class name
----------------------------------------------1: 4559 435672 [C2: 419 135984 [B3: 4410 105840 java.lang.String4: 706 80880 java.lang.Class5: 632 41512 [Ljava.lang.Object;6: 791 31640 java.util.TreeMap$Entry7: 628 25120 java.util.LinkedHashMap$Entry8: 426 18992 [Ljava.lang.String;9: 373 11936 java.util.HashMap$Node10: 24 8640 [Ljava.util.HashMap$Node;11: 113 8136 java.lang.reflect.Field12: 135 7720 [I13: 87 5568 java.net.URL14: 110 4400 java.lang.ref.SoftReference15: 256 4096 java.lang.Integer16: 121 3872 java.util.Hashtable$Entry17: 105 3360 java.util.concurrent.ConcurrentHashMap$Node18: 8 3008 java.lang.Thread19: 42 2352 sun.misc.URLClassPath$JarLoader20: 26 2080 java.lang.reflect.Constructor21: 16 2048 [Ljava.util.concurrent.ConcurrentHashMap$Node;22: 39 1872 sun.util.locale.LocaleObjectCache$CacheEntry23: 43 1720 java.lang.ref.Finalizer24: 34 1632 java.util.HashMap25: 1 1568 [[B26: 37 1480 java.io.ObjectStreamField27: 26 1456 java.lang.Class$ReflectionData28: 89 1424 java.lang.Object29: 20 1280 java.util.concurrent.ConcurrentHashMap30: 15 1200 [Ljava.util.WeakHashMap$Entry;31: 9 1184 [Ljava.util.Hashtable$Entry;32: 2 1064 [Ljava.lang.invoke.MethodHandle;33: 1 1040 [Ljava.lang.Integer;34: 1 1040 [[C35: 41 984 java.io.ExpiringCache$Entry36: 15 840 sun.nio.cs.UTF_8$Encoder37: 12 768 java.util.jar.JarFile38: 19 760 sun.util.locale.BaseLocale$Key39: 15 720 java.util.WeakHashMap40: 22 704 java.lang.ref.ReferenceQueue41: 7 672 java.util.jar.JarFile$JarFileEntry42: 12 672 java.util.zip.ZipFile$ZipFileInputStream43: 11 648 [Ljava.lang.reflect.Field;44: 8 640 [S45: 19 608 java.io.File46: 19 608 java.util.Locale47: 19 608 sun.util.locale.BaseLocale48: 13 520 java.security.AccessControlContext49: 21 504 java.util.jar.Attributes$Name50: 19 456 java.util.Locale$LocaleKey51: 18 432 sun.misc.MetaIndex52: 10 400 java.io.FileDescriptor53: 10 400 sun.nio.cs.UTF_8$Decoder54: 13 392 [Ljava.io.ObjectStreamField;55: 1 384 com.intellij.rt.execution.application.AppMainV2$156: 1 384 java.lang.ref.Finalizer$FinalizerThread57: 24 384 java.lang.ref.ReferenceQueue$Lock58: 6 384 java.nio.DirectByteBuffer59: 12 384 java.util.zip.ZipCoder60: 1 376 java.lang.ref.Reference$ReferenceHandler61: 18 352 [Ljava.lang.Class;62: 6 336 java.nio.DirectLongBufferU63: 10 320 java.lang.OutOfMemoryError64: 3 312 [D65: 2 312 [J66: 13 312 [Ljava.lang.reflect.Constructor;67: 13 312 sun.reflect.NativeConstructorAccessorImpl68: 12 288 java.util.ArrayDeque69: 5 280 sun.util.calendar.ZoneInfo70: 3 264 java.lang.reflect.Method71: 11 264 java.net.StandardSocketOptions$StdSocketOption72: 11 264 java.util.ArrayList73: 8 256 java.util.Vector74: 3 240 [Ljava.lang.ThreadLocal$ThreadLocalMap$Entry;75: 5 240 java.util.Hashtable76: 6 240 java.util.WeakHashMap$Entry77: 7 224 java.lang.ThreadLocal$ThreadLocalMap$Entry78: 4 224 java.util.LinkedHashMap79: 9 216 java.util.LinkedList$Node80: 13 208 sun.reflect.DelegatingConstructorAccessorImpl81: 5 200 java.security.ProtectionDomain82: 6 192 java.io.FileInputStream83: 4 192 java.util.Properties84: 4 192 java.util.TreeMap85: 2 160 [[Ljava.lang.String;86: 4 160 java.lang.ClassLoader$NativeLibrary87: 5 160 java.security.CodeSource88: 5 160 java.util.LinkedList89: 5 160 sun.util.locale.provider.LocaleProviderAdapter$Type90: 3 144 java.nio.HeapByteBuffer91: 6 144 sun.misc.PerfCounter92: 3 144 sun.misc.URLClassPath93: 2 128 java.io.ExpiringCache$194: 4 128 java.util.Stack95: 2 128 sun.nio.cs.ext.DoubleByte$Encoder96: 1 120 java.net.SocksSocketImpl97: 5 120 java.util.Collections$UnmodifiableRandomAccessList98: 5 120 sun.misc.FloatingDecimal$PreparedASCIIToBinaryBuffer99: 2 112 java.lang.Package100: 7 112 java.util.HashSet101: 2 112 java.util.ResourceBundle$CacheKey102: 2 112 java.util.zip.ZipFile$ZipFileInflaterInputStream103: 2 112 sun.nio.cs.ext.DoubleByte$Decoder104: 3 96 java.io.FileOutputStream105: 4 96 java.lang.RuntimePermission106: 3 96 java.lang.StringCoding$StringEncoder107: 2 96 java.lang.ThreadGroup108: 6 96 java.lang.ThreadLocal109: 1 96 java.net.DualStackPlainSocketImpl110: 2 96 java.util.ResourceBundle$BundleReference111: 2 96 java.util.zip.Inflater112: 4 96 jdk.net.ExtendedSocketOptions$ExtSocketOption113: 1 96 sun.misc.Launcher$AppClassLoader114: 3 96 sun.net.spi.DefaultProxySelector$NonProxyInfo115: 2 96 sun.nio.cs.StreamEncoder116: 1 88 sun.misc.Launcher$ExtClassLoader117: 5 80 [Ljava.security.Principal;118: 2 80 java.io.BufferedWriter119: 2 80 java.io.ExpiringCache120: 5 80 java.security.ProtectionDomain$Key121: 2 80 sun.misc.FloatingDecimal$BinaryToASCIIBuffer122: 3 72 java.lang.ThreadLocal$ThreadLocalMap123: 3 72 java.net.Proxy$Type124: 3 72 java.util.Arrays$ArrayList125: 1 72 java.util.ResourceBundle$RBClassLoader126: 3 72 java.util.concurrent.atomic.AtomicLong127: 3 72 sun.misc.FloatingDecimal$ExceptionalBinaryToASCIIBuffer128: 1 72 sun.util.locale.provider.JRELocaleProviderAdapter129: 1 64 [F130: 2 64 [Ljava.lang.Thread;131: 2 64 java.io.FilePermission132: 2 64 java.io.PrintStream133: 2 64 java.lang.ClassValue$Entry134: 2 64 java.lang.StringCoding$StringDecoder135: 2 64 java.lang.VirtualMachineError136: 2 64 java.lang.ref.ReferenceQueue$Null137: 2 64 java.lang.ref.WeakReference138: 2 64 java.security.BasicPermissionCollection139: 2 64 java.security.Permissions140: 2 64 java.util.ResourceBundle$LoaderReference141: 2 48 [Ljava.lang.reflect.Method;142: 2 48 java.io.BufferedOutputStream143: 1 48 java.io.BufferedReader144: 2 48 java.io.File$PathStatus145: 2 48 java.io.FilePermissionCollection146: 2 48 java.io.OutputStreamWriter147: 2 48 java.net.InetAddress$Cache148: 2 48 java.net.InetAddress$Cache$Type149: 1 48 java.net.SocketInputStream150: 1 48 java.nio.HeapCharBuffer151: 2 48 java.nio.charset.CoderResult152: 3 48 java.nio.charset.CodingErrorAction153: 3 48 java.util.Collections$UnmodifiableSet154: 3 48 java.util.HashMap$KeySet155: 2 48 java.util.zip.ZStreamRef156: 2 48 sun.misc.NativeSignalHandler157: 2 48 sun.misc.Signal158: 3 48 sun.net.www.protocol.jar.Handler159: 1 48 sun.nio.cs.StreamDecoder160: 1 48 sun.nio.cs.US_ASCII$Decoder161: 1 48 sun.util.locale.provider.LocaleResources$ResourceReference162: 1 48 sun.util.resources.TimeZoneNames163: 1 48 sun.util.resources.en.TimeZoneNames_en164: 1 40 [Lsun.util.locale.provider.LocaleProviderAdapter$Type;165: 1 40 java.io.BufferedInputStream166: 1 40 java.util.ResourceBundle$1167: 1 40 sun.nio.cs.StandardCharsets$Aliases168: 1 40 sun.nio.cs.StandardCharsets$Cache169: 1 40 sun.nio.cs.StandardCharsets$Classes170: 1 40 sun.nio.cs.ext.ExtendedCharsets171: 1 32 [Ljava.lang.OutOfMemoryError;172: 2 32 [Ljava.lang.StackTraceElement;173: 1 32 [Ljava.lang.ThreadGroup;174: 1 32 [Ljava.net.Proxy$Type;175: 1 32 java.io.WinNTFileSystem176: 1 32 java.lang.ArithmeticException177: 2 32 java.lang.Boolean178: 1 32 java.lang.NullPointerException179: 1 32 java.net.InetAddress$InetAddressHolder180: 1 32 java.net.Socket181: 2 32 java.nio.ByteOrder182: 2 32 java.util.LinkedHashMap$LinkedKeySet183: 2 32 java.util.concurrent.atomic.AtomicInteger184: 1 32 java.util.concurrent.atomic.AtomicReferenceFieldUpdater$AtomicReferenceFieldUpdaterImpl185: 1 32 jdk.net.ExtendedSocketOptions$1186: 1 32 sun.instrument.InstrumentationImpl187: 1 32 sun.nio.cs.StandardCharsets188: 1 32 sun.util.locale.provider.LocaleResources189: 1 32 sun.util.locale.provider.LocaleServiceProviderPool190: 1 24 [Ljava.io.File$PathStatus;191: 1 24 [Ljava.lang.ClassValue$Entry;192: 1 24 [Ljava.net.InetAddress$Cache$Type;193: 1 24 [Ljava.security.ProtectionDomain;194: 1 24 [Lsun.launcher.LauncherHelper;195: 1 24 java.io.InputStreamReader196: 1 24 java.lang.ClassValue$Version197: 1 24 java.lang.StringBuilder198: 1 24 java.lang.invoke.MethodHandleImpl$4199: 1 24 java.lang.reflect.ReflectPermission200: 1 24 java.net.Inet4Address201: 1 24 java.net.Inet6AddressImpl202: 1 24 java.net.Proxy203: 1 24 java.util.BitSet204: 1 24 java.util.Collections$EmptyMap205: 1 24 java.util.Collections$SetFromMap206: 1 24 java.util.Collections$SynchronizedSet207: 1 24 java.util.Locale$Cache208: 1 24 java.util.ResourceBundle$Control$CandidateListCache209: 1 24 java.util.jar.Manifest210: 1 24 sun.instrument.TransformerManager211: 1 24 sun.launcher.LauncherHelper212: 1 24 sun.misc.JarIndex213: 1 24 sun.misc.URLClassPath$FileLoader214: 1 24 sun.nio.cs.ISO_8859_1215: 1 24 sun.nio.cs.ThreadLocalCoders$1216: 1 24 sun.nio.cs.ThreadLocalCoders$2217: 1 24 sun.nio.cs.US_ASCII218: 1 24 sun.nio.cs.UTF_16219: 1 24 sun.nio.cs.UTF_16BE220: 1 24 sun.nio.cs.UTF_16LE221: 1 24 sun.nio.cs.UTF_8222: 1 24 sun.nio.cs.ext.GBK223: 1 24 sun.reflect.NativeMethodAccessorImpl224: 1 24 sun.util.locale.BaseLocale$Cache225: 1 24 sun.util.locale.provider.TimeZoneNameProviderImpl226: 1 16 [Ljava.lang.Throwable;227: 1 16 [Ljava.security.cert.Certificate;228: 1 16 [Lsun.instrument.TransformerManager$TransformerInfo;229: 1 16 java.io.FileDescriptor$1230: 1 16 java.lang.CharacterDataLatin1231: 1 16 java.lang.ClassValue$Identity232: 1 16 java.lang.Runtime233: 1 16 java.lang.String$CaseInsensitiveComparator234: 1 16 java.lang.System$2235: 1 16 java.lang.Terminator$1236: 1 16 java.lang.invoke.MemberName$Factory237: 1 16 java.lang.invoke.MethodHandleImpl$2238: 1 16 java.lang.invoke.MethodHandleImpl$3239: 1 16 java.lang.ref.Reference$1240: 1 16 java.lang.ref.Reference$Lock241: 1 16 java.lang.reflect.ReflectAccess242: 1 16 java.net.InetAddress$2243: 1 16 java.net.URLClassLoader$7244: 1 16 java.nio.Bits$1245: 1 16 java.nio.charset.CoderResult$1246: 1 16 java.nio.charset.CoderResult$2247: 1 16 java.security.ProtectionDomain$2248: 1 16 java.security.ProtectionDomain$JavaSecurityAccessImpl249: 1 16 java.util.Collections$EmptyIterator250: 1 16 java.util.Collections$EmptyList251: 1 16 java.util.Collections$EmptySet252: 1 16 java.util.Hashtable$EntrySet253: 1 16 java.util.ResourceBundle$Control254: 1 16 java.util.WeakHashMap$KeySet255: 1 16 java.util.concurrent.atomic.AtomicBoolean256: 1 16 java.util.jar.Attributes257: 1 16 java.util.jar.JavaUtilJarAccessImpl258: 1 16 java.util.zip.ZipFile$1259: 1 16 jdk.net.ExtendedSocketOptions$PlatformSocketOptions260: 1 16 sun.misc.ASCIICaseInsensitiveComparator261: 1 16 sun.misc.FloatingDecimal$1262: 1 16 sun.misc.Launcher263: 1 16 sun.misc.Launcher$Factory264: 1 16 sun.misc.Perf265: 1 16 sun.misc.Unsafe266: 1 16 sun.net.spi.DefaultProxySelector267: 1 16 sun.net.www.protocol.file.Handler268: 1 16 sun.reflect.DelegatingMethodAccessorImpl269: 1 16 sun.reflect.ReflectionFactory270: 1 16 sun.util.calendar.Gregorian271: 1 16 sun.util.locale.provider.AuxLocaleProviderAdapter$NullProvider272: 1 16 sun.util.locale.provider.SPILocaleProviderAdapter273: 1 16 sun.util.locale.provider.TimeZoneNameUtility$TimeZoneNameGetter274: 1 16 sun.util.resources.LocaleData275: 1 16 sun.util.resources.LocaleData$LocaleDataResourceBundleControl
Total 15169 990792
可以看到最多的对象是String、Class、Object、HashMap。。。
八、性能分析-每秒1000并发的情况下该如何设置jvm的内存?
1、大型购物网站的日常的QPS是多少?
大约是1000QPS
平时购物高峰期,一般集中在2个时间段:11:30—13:30和19:30—21:30
高峰时间段的浏览量PV都是百万级以上,高峰期的QPS约500—1000,我们就按1000来计算。
如果按QPS=1000,1000*3600秒,那一个小时=360万的PV,即每个高峰期2个小时约700万的PV。
2、QPS=1000大概需要多少内存?JVM设置多大?
用户访问一页有10条商品,故每次的response=10条。现在要估算,每条大约多少字节?
假设每件商品最多10个字段(标题、价格、缩略图、原价、点击购物等等),平均每个字段100字节,大约1KB的数据。
那每次访问一页大约是10*1KB=10KB
1000QPS大约需要多少内存?
1000QPS=1000*10KB=10M,也就是说每秒大约需要占用10M的内存数据。
3、QPS=1000多久触发一次ygc?
多久触发一次ygc是由你的堆内存决定的,堆内存够的话时间就长点,堆内存不够的话就短点。
假设我们按1分钟1次触发一次ygc,大约需要配置多少内存?
1s=10m,1min=60*10m=600m
按照young:old=1:2=600:1200,则需要1800M才会1分钟触发1次ygc,所以我们把堆大小设置为2G就能保证分钟级别的GC次数。(如果要2分钟一次ygc,设置为4G)
4、部署多少台机器合适?
按照前面的分析,部署多少台没有太多要求,因为单台已经能支撑1000QPS了。
但为了防止单点故障,提升高可用,一般部署2台。每台承接500QPS。
5、先评估再压测
九、性能分析-系统并发量,突然猛增100倍,该如何解决?
在双十一情况下,浏览量突增
1、从另一个角度思考:我的系统最大并发是多少。即系统每秒最大能处理多少个请求?
(1)单次请求的处理时间=50ms(在互联网公司,所有暴露在公网的接口,都必须低于100ms以下)
(2)那单条线程1s内能处理请求数=1000/50=20次
(3)那有多少条线程呢?
springcloud底层是springboot,springboot底层是tomcat
tomcat底层的线程池,最大的线程数默认是200线程
(4)所以一个微服务,200条线程,每条线程的QPS=20,那整体就是200*20=4000,4000是最大值。
你的服务每秒最大能支撑4000个并发
2、那现在引发另一个问题:能不能优化?能不能再高点?
基本不可能了,一般tomcat200个线程,够大了。
如果50ms是纯CPU计算的,即CPU密集型,CPU只有2核就会出问题的。
什么是CPU密集型?
就是for循环,然后加减乘除的算。
怎么知道CPU密集型?
一般看代码,或者CPU,CPU如果是100%,一般就是。
如果不是纯CPU计算,即IO密集型,问题不大。(什么是IO密集型?就是网络IO或磁盘IO计算)
所以单个服务优化不了,4000并发够可以了
3、4000个并发,jvm运行状况如何?
每次请求约10KB,每秒4000并发=4000*10KB=40MB
年轻代600M / 40M = 15s,即约15s会触发ygc,问题也不大,所以堆设置2G也能支撑4000QPS
4、流量突增100倍并发,如何支撑?
日常请求时1000QPS,突增100倍=10万QPS。
单台理论最大值是4000QPS,10万 / 4000 = 25倍,即25台。
所以我们最起码,要动态新增25台服务来支撑100倍的并发。
如果是CPU密集型计算的,增加的台数绝对大于25台,可能是50台或更高,这个要根据压测来判断。
5、25台机器去那里搞?
答案是:停服务
停其他不重要的服务,例如双11当天,就把不重要的服务停掉,例如退货服务、积分服务、评价服务等等。
事先计划好,一旦大促开始,就把这些不重要的服务停掉。
把服务器腾出来,给例如商品服务这种大促使用,保证大促顺利进行。
Java基础之《JVM性能调优(3)—堆》相关推荐
- Netty解决TCP粘包/拆包导致的半包读写问题
一.TCP粘包/拆包问题说明 TCP是个"流"协议,就是没有界限的一串数据.TCP底层并不了解上层业务数据的具体含义,它会根据TCP缓冲区的实际情况进行包拆分,所以在业务上认为,一 ...
- Netty学习总结(5)——Netty之TCP粘包/拆包问题的解决之道
无论是服务端还是客户端,读取或者发送消息的时候,都需要考虑TCP底层的粘包/拆包机制. TCP粘包/拆包 TCP是个"流"协议. 流:没有界限的一串数据.如同河里的流水,它们是连成 ...
- netty解决TCP粘包/拆包导致的半包读写问题的三种方案
解决方案一:LineBasedFrameDecoder+StringDecoder来解决TCP的粘包/拆包问题 只需要在客户端和服务端加上45.46两行代码并且在发送消息的时候加上换行符即可解决TCP ...
- Java基础之《netty(28)—TCP粘包拆包原理》
一.基本介绍 1.TCP是面向连接的,面向流的,提供高可靠性服务.收发两端(客户端和服务器端)都要有一一成对的socket,因此,发送端为了将多个发给接收端的包,更有效的发给对方,使用了优化方法(Na ...
- Netty 之 TCP粘包拆包场景
转自:http://blog.csdn.net/z69183787/article/details/52595980 TCP编程底层都有粘包和拆包机制,因为我们在C/S这种传输模型下,以TCP协议传输 ...
- Netty(二)——TCP粘包/拆包
转载请注明出处:http://www.cnblogs.com/Joanna-Yan/p/7814644.html 前面讲到:Netty(一)--Netty入门程序 主要内容: TCP粘包/拆包的基础知 ...
- java tcp怎么拆包_Java网络编程基础之TCP粘包拆包
TCP是个"流"协议,所谓流,就是没有界限的一串数据.大家可以想象河里的流水,他们是连成一片的,其间并没有分界线.TCP底层并不了解上层业务数据的具体含义,他会根据TCP缓冲区的实 ...
- 《精通并发与Netty》学习笔记(13 - 解决TCP粘包拆包(一)概念及实例演示)
一.粘包/拆包概念 TCP是一个"流"协议,所谓流,就是没有界限的一长串二进制数据.TCP作为传输层协议并不不了解上层业务数据的具体含义,它会根据TCP缓冲区的实际情况进行数据包的 ...
- Netty详解(五):Netty TCP粘包 拆包
1. 概述 无论是服务端还是客户端,我们读取或者发送消息的时候,都需要考虑TCP底层的粘包和拆包机制.下面我们来通过Netty来详解TCP底层的粘包和拆包机制. 2. TCP底层的粘包和拆包机制 TC ...
- 一起学Netty(六)之 TCP粘包拆包场景
TCP编程底层都有粘包和拆包机制,因为我们在C/S这种传输模型下,以TCP协议传输的时候,在网络中的byte其实就像是河水,TCP就像一个搬运工,将这流水从一端转送到另一端,这时又分两种情况: 1)如 ...
最新文章
- vector相关习题
- 【重复制造精讲】1、入门介绍
- Hard Calculation 模拟(200)
- java自定义返回码_java – 自定义HTTP状态代码
- 刪數 (Standard IO)
- java transaction cn_GitHub - cnzebra/tcc-transaction: tcc-transaction是TCC型事务java实现
- jQuery使用CDN加速
- 18000 6c java_面向ISO18000-6C协议的无源超高频射频识别标签芯片设计
- 在c语言中数组下标的最小值,数组元素下标的上限_c语言中,数组元素的下标下限为...
- 问题:连接查询和子查询的区别和连接及优劣?
- postgresql安装过程小记
- .NET图像处理包 DotImage
- WEB前端--Day9(动画)
- python中base函数_详细的python basemap中各函数的所有参量注释
- 西藏计算机一级,西藏计算机等级考试级别
- C++:高斯坐标,大地坐标转经纬度
- 「实时视频流分析的边缘计算技术」最新2022研究综述
- python云盘私有云_GitHub - 0x2642/Umi-Chest: 一个基于python的私有云实验项目
- 文字检测与识别1-MSER
- mysql 单表关联_MySQL 基础之 单表、多表联查
热门文章
- custom_dataset
- husky v8 lint-stage eslint
- 八数码 BFS+HASH
- 厦门理工学院oj 1107-牲口棚的安全
- ios 绘制线框_16款值得一用的iPhone线框图模板 (PSD Sketch)
- java pnpoly算法_PNPoly算法代码例子,判断一个点是否在多边形里面
- 信息安全的江湖 只有圈内人玩的转
- 平方预测误差(Squared prediction error,SPE)和霍特林统计量(Hotelling’s T2)原理
- Windows系统中设置软件的开机自动启动
- “解决Python软件包安装问题 - 修改pip源地址“