juc:java util concurrent
jvm:java virtual machine
jvm参数性能调优:
native method stack:用来加载第三方库,如调用c/c++
program counter register: 指针,用于记载程序执行的位置
每个线程都有一个程序计数器,是线程私有的,就是一个指针,指向方法区中的的方法字节码(用来存储下一条指令的地址,
即为即将要执行的指令代码的地址),用以完成分支、循环、跳转、异常处理、线程恢复
method area(方法区):存储每一个类的结构信息。方法区是规范,在不同虚拟机里实现是不一样的。典型例子为永久代和元空间
重点:
java stack:栈管运行
栈保存的内容:
8种基本类型的变量+对象的引用变量+
本地变量:输入参数和输出参数以及方法内的变量
栈操作:记录出栈、入栈
栈帧数据:包括类文件、方法
java的方法称为栈帧(main方法一定在栈顶底,pop出执行)
heap:堆管存储
双亲委派模型:
沙箱安全机制:
gc:
java8:永久代改为与元空间
元空间与永久代之间最大的区别在于:
永久带使用的JVM的堆内存,但是java8以后的元空间并不在虚拟机中而是使用本机物理内存。
默认情况下:元空间的大小受本地内存限制,类的元数据放入native memory,字符串池和静态变量放入java堆中,这样可以加载多少类的元数据
就不再由MaxPermSize控制,而是由系统的实际可用看空间来控制
堆内存调优简介:
-Xms:设置初始分配大小,默认为物理内存的1/64
-Xmx:最大分配内存,默认为物理内存的1/4
-XX:PrintGCDetails:输出详细的GC处理日志
-xx:MaxTenuringThreshold: 设置对象在新生代中存活的次数
public static void main(String args[])
{
long maxMemory = RUntime.getRuntime().maxMemory();//返回java虚拟机试图使用的最大内存量
long totalMeomory = RUntime.getRuntime().totalMeomory();//返回java虚拟机中的内存总量
}
在实际生产中,通产将-Xms和-Xmx设置一样大小,避免系统不停的分配内存大小导致系统卡顿。
psYoungGen+parOldGen+metespace=totalMemory = maxMemory
gc =====> full gc =======> outOfMemoryError: heap space
较小收集:新生代
较大收集:old区
普通gc(minor gc || gc):只针对新生代区域的GC,指发生在新生代的垃圾收集动作,因为大多数的java对象的存活率不高,
所以minor gc非常频繁,一般回收速度也比较快
全局gc(major gc || full gc):发生在老年代(jdk7)||元空间(jdk8),full gc的速度比gc慢十几倍。
gc四大算法: 1 引用计数法:当有人引用这个类就+1,有人不引用了就-1.缺点:每次对象赋值时均要维护引用计数器,且计数器本身也有一定的消耗,
且也较难处理循环引用。
2 复制算法(copying):年轻代中使用的是minor gc,复制算法的基本思想就是内存分为两块,每次只用其中的一块,当一块内存使用完,就将还活着的独享复制到另外一块上面,
复制算法不会产生内存碎片。原理:从根集合(Gc Root)开始,通过tracing从from中找到存活对象,拷贝到to中;from和to交换身份,下次分配从to开始.
缺点:他浪费了一半的内存,如果对象的存活率很高,那么复制的比率太高而导致gc性能变差。
3 标记清除(mark-sweep):老年代一般是由标记清除或者是标记清除与标记整理的混合。算法分成标记和清除两个阶段,先标记出要回收的对象,然后统一回收这些对象。
优点:不需要额外的空间 缺点:两次扫描,耗时严重,并且会产生内存碎片
4 标记压缩(mark-compact):第一步:与标记清除一样,再次扫描,并往一段滑动存活对象,达到连续空间的内存区域,没有了内存碎片
优点:没有内存碎片产生,但是进行压缩为连续空间时耗时
分代收集算法:
年轻代 ======> 复制算法
老年代 ======> 标记压缩算法
耗时短没碎片的算法存在吗?
在java9中存在,为G1算法
JMM:(java memory model)是一种抽象概念,并不真实存在。
JVM运行程序的实体是线程,而每个线程创建是JVM都会为其创建一个工作内存(也称为栈空间),工作内存是每个线程的私有数据区域,而java的内存模型中归定所有的变量都存储在主内存,
主内存是共享内存区域,所有线程都可以访问,但是线程对变量的操作(读取赋值等)必须在工作内存中进行,首先要将变量从主内存拷贝到自己的线程工作内存空间对变量进行操作,结束后将新的值
写回到主内存中,不能直接操作主内存的变量。各个线程的工作内存中存储着主内存的变量副本拷贝,因此不同的线程间无法访问对方的工作内存,线程间的通信必须同过共享内部才能完成。
可见性:
原子性:
有序性:
volatile:java虚拟机提供的轻量级的同步机制
code example:
class MyNumber{
int number = 10;
public void addTo125{
this.number = 125;
}
}
JMM =可见性(通知机制)
A线程修改了变量值,同过JMM的可见性达到值修改后主线程知道了值被修改了
class Test{
public static void main(String[] args) {
MyNumber myNumber = new MyNumber();
new Thread(()=>{
try {
Thread.sleep(3000);
} catch(Exception e) {
e.printStackTrace();
}
myNumber.addTo125();
System.out.println("mynumber value"+myNumber.number);
},'a').start();
}
while(myNumber.number == 10){
}
System.out.println(Thread.currentThread().getName()+"over");
}
网友评论