jvm学习总结
1、程序计数器
2、虚拟机栈
2.1、定义
控制栈的大小
Xss256kb // 命令行参数
2.2、线程诊断
top 命令查看cpu运行情况
ps H -eo pid,tid,%cpu |grep 进程ID
2.3、线程死锁
void function(){
while(true){
// 方法一直循环不断地运行
}
}
3、本地方法栈
Java 中使用native修饰的方法,说明这个方法是在本地方法区。
public class Object{
public native Object clone(){
}
}
4、堆
4.1、定义
控制堆内存的大小
Xmx8m
4.2、堆内存溢出
4.3、堆内存诊断
package com.bubaiwantong.heap;
import java.util.ArrayList;
public class Demo02 {
public static void main(String[] args) {
ArrayList students = new ArrayList();
try {
Thread.sleep(30000);
for (int i = 0; i
5、方法区
5.1、定义
5.2、JDK版本比较
- 1.8之前方法区在JVM内部
- 1.8止呕方法区变成了元空间
永久代
- -XX:MaxPermSize=8m
package com.bubaiwantong.method;
import jdk.internal.org.objectweb.asm.ClassWriter;
import jdk.internal.org.objectweb.asm.Opcodes;
/**
* 配置VM参数
* -XX:MaxPermSize=8m
*/
public class Demo02 extends ClassLoader{
public static void main(String[] args) {
int count=0;
try {
Demo02 test = new Demo02();
for (int i = 0; i
元空间
- 配置VM参数
- -XX:MaxMetaspaceSize=8m
package com.bubaiwantong.method;
import jdk.internal.org.objectweb.asm.ClassWriter;
import jdk.internal.org.objectweb.asm.Opcodes;
/**
* 配置VM参数
* -XX:MaxMetaspaceSize=8m
*/
public class Demo01 extends ClassLoader{
public static void main(String[] args) {
int count=0;
try {
Demo01 test = new Demo01();
for (int i = 0; i
5.4、运行时常量池
- 常量池,就是一张表,虚拟机指令根据这张常量表找到要执行的类名、方法名、参数类型、字面量等信息
- 运行时常量池,常量池是*.class文件中的,当该类被加载,它的常量池信息就会放入运行时常量池,并把里面的符号地址变为真实地址。
5.5、StringTable特性
串池讲解没有听懂,可以听下这个课程
package com.bubaiwantong.compile;
public class Demo03 {
public static void main(String[] args) {
// ["ab","a","b"]
String x = "ab";
String s = new String("a") + new String("b");
// 堆 new String("a") new String("b") new String("ab")
String s2= s.intern();
// 将这个字符串对象尝试放入到串池,如果有则并不放入,如果没有则放入串池,会把串池中的对象返回。
System.out.println(s2 == x); // true 串池已经有"ab",所以直接取出来,和x相等
System.out.println(s == x); // false 这个是new String("ab")的对象,所以与“ab”并不相等
// 归根结底还是看 == 比较的什么吧,== 判断连个对象的地址是否相等,而并不是判断两个对象的值相等。
}
}
1) 调换位置
String x2=new String("c")+new String("d");
x2.intern(); // 将"cd"放入到串池中,然后x1将会从串池中取出"cd",所以这是两个相同的对象。
String x1= "cd";
System.out.println(x1 == x2); // true
2) JDK1.6
// jdk 1.6
String x2=new String("c")+new String("d");
x2.intern(); // 会将“cd”复制一份到串池中,也就是说把复制一份副本到串池中,而自己还在堆中,所以这两个x1和x2不是一个对象
String x1= "cd";
System.o服务器托管网ut.println(x1 == x2); // false
总结一下:intern()在jdk1.6执行,如果串池中没有,会复制一个副本,也就是说会新建一个对象吧,所以地址值也会不一样。
而在jdk1.8执行的时候,intern()这个函数会将x2自己放进去,所以当x1去取得时候,x1与x2会相等。
6、直接内存
6.1、定义
- 直接内存 这块内存由可以说是共享内存,Java虚拟机和操作系统都可以访问
6.2、分配和回收原理
- 使用了Unsafe对象完成了直接内存的分配回收,并且回收需要主动调用freeMemory方法
- ByteBuffer的实现类内部,使用了Cleaner(虚引用)来监测ByteBuffer对象,一旦ByteBuffer对象被垃圾回收,那么就会由ReferenceHandler线程通过Cleaner的clean方法调用freeMemory来释放直接内存。
import sun.misc.Unsafe;
import java.io.IOException;
import java.lang.reflect.Field;
/**
* 直接内存 这块内存由可以说是共享内存,Java虚拟机和操作系统都可以访问
*/
public class Demo03 {
static int _1GB = 1024*1024*1024;
public static void main(String[] args) throws IOException {
Unsafe unsafe= getUnsafe();
long base = unsafe.allocateMemory(_1GB); // 获取分配内存的地址
unsafe.setMemory(base,_1GB,(byte ) 0); // 分配内存
System.in.read()服务器托管网;
unsafe.freeMemory(base); // 释放内存
System.in.read();
}
public static Unsafe getUnsafe(){
try {
Field f = Unsafe.class.getDeclaredField("theUnsafe");
f.setAccessible(true);
Unsafe unsafe = (Unsafe ) f.get(null);
return unsafe;
} catch (Exception e) {
e.printStackTrace();
}
return null;
}
}
- 禁用显示的垃圾回收
-Xx:+DisableExplicitGC //显示的
服务器托管,北京服务器托管,服务器租用 http://www.fwqtg.net
机房租用,北京机房租用,IDC机房托管, http://www.fwqtg.net
每次聊到代码优化,都会有很多人说理论、架构、核心思路,其实我觉得代码优化这事说简单也很简单,说复杂吧它也有一定的难度。 写代码首选得遵循一个良好的编码习惯,今天分享一下我认为几个不错的代码优化小技巧,看完以后你的小伙伴也会说我你的代码像诗。 1. 定义配置文件…