享学堂-架构师网课笔记-JVM-L2

笔记

运行加载

1,jvm的运行流程,先往操作系统中申请一块连续的内存空间,根据内存大小找到具体分配表,根据内存的起始位置和终止位置分配给jvm然后jvm进行内部分配。
2,jvm根据运行参数分配堆,方法区和堆内存的空间大小
3,类加载,加载类信息到方法区,还有类中的静态变量也要加入方法区
4,执行方法区创建对象,运行main方法线程,创建栈空间
在这里插入图片描述


	 static class Teacher{
		String name;

		public String getName() {
			return name;
		}

		public void setName(String name) {
			this.name = name;
		}
	}
	public static void main(String[] args) {
			Teacher t1=new Teacher();
			t1.setName("zhangsan");
			Teacher t2=new Teacher();
			t2.setName("lisi");
	}

像上面的代码程序开始时会在堆中新建一个Teacher对象,然后方法栈中的变量变会引用到堆内存中的t1,同样堆中新建一个Teacher对象,然后方法栈中变量表也会对应一个存在一个变量指向t2。这样数据的真实存在是在堆中,而栈只是指向堆中的一个地址而已。

堆空间

上面讲到了堆空间是对象的实际存放位置,而堆存放的位置分开了下面四个区域为 Eden 和 Survivor 区,最后 Survivor 由 From Survivor 和 To Survivor,之所以要分开四个区域是根据每个区域的对象性质不同,有的经常被其他栈引用,有的不被引用所以对应的GC算法也不同,我想作者这样设计可能为了减少GC性能的开销。
在这里插入图片描述
像下面这段代码,当一个对象被新建时会存在堆中在eden区新建一个对象,当进行垃圾回收时,如果该对象没有被回收,则会被放进From区,如果还是没回收则回进入to区,最后进入到Tenured区及老年代。

public class JVMObject {
    public final static String MAN_TYPE = "man"; // 常量
    public static String WOMAN_TYPE = "woman";  // 静态变量
    public static void  main(String[] args)throws Exception {
        Teacher T1 = new Teacher();
        T1.setName("Mark");
        T1.setSexType(MAN_TYPE);
        T1.setAge(36);
        for(int i =0 ;i<15 ;i++){
            System.gc();//主动触发GC 垃圾回收 15次--- T1存活
        }
        Teacher T2 = new Teacher();
        T2.setName("King");
        T2.setSexType(MAN_TYPE);
        T2.setAge(18);
        Thread.sleep(Integer.MAX_VALUE);//线程休眠
    }
}
}

在这里插入图片描述
以上可以对堆和栈进行一个简单的对比:

堆存活周期比较长,对象的生命周期划分有新生代老年代等栈的生命周期较短,作用于方法中,一般方法执行完就结束
内存空间较大内存空间教小
线程共享线程独享

栈之间的数据共享

栈和栈之间调用方法时,如果有数据的传参,则栈与栈之间会有内存共享,即操作数栈会和上面的重合一起这样就可以起到节约空间的效果。
在这里插入图片描述

JHSDB 中查看对象

JHSDB是window的一个查看内存地址运用的工具,进入Java的根目录地址执行 java -cp .\sa-jdi.jar sun.jvm.hotspot.HSDB,然后就会打开一个新窗口,输入进程号就可以查看内存运行状态,本人用mac就不验证了。
在这里插入图片描述

内存溢出

既然JVM帮我们管理了内存,但是它还是会存在内存溢出的情况,既然分了三块内存区域,则会有三种情况的内存溢出,分别是:
栈溢出:OutOfMemoryError 不断新建线程,不断创建方法栈导致机器内存不足,会影响整个机器性能,因为虚拟机对栈空间的总大小是不设限制的,只对单个栈空间大小设置大小,所以会影响整体机器性能 。
堆溢出:申请的内存空间不够用,通过 调大 -Xms,-Xmx 参数,堆空间是对象的存活管理空间,如果堆空间不够大,说明数据结构等可能存在问题,对象回收不及时,某些对象存在时间过长需要优化代码,如果不能则只能申请更多的内存。
方法区溢出:方法区是存放类加载信息的地方,一般方法区溢出类回收不及时,类的回收比较复杂,,也有可能是项目太大,加载的类太多导致。

运行是常量池

运行时常量池是运行在虚拟机中当类加载完毕后将class定义后的常量对象放到运行时常量池中,让其他对象引用。

String 和字符串常量池

String 是对char的一个封装,本身是不可变化的,这样设计可能因为Java中使用最多的数据类型之一,所以做了特别的优化对String特别设计了一个字符串常量池,用于管理它的生存空间。这样做有一下好处:

  • String的安全性,不易被修改
  • 保证hash不变性,在用到hash的数据结构时保证key-value的一致性
  • 可以实现字符串常量池,统一管理,String 的实现方式有两种,一种是直接String a="abc"; 这种是在常量池中新建,另外一种是String a=new String("abc"); 这种是在方法堆中新建。

在这里插入图片描述

String str=“abc”;

当使用这种方法创建时会在常量池创建对象,如果常量池中已经存在创建好的对象则会遍历常量池然后直接引用,从而减少重复创建节约内存
在这里插入图片描述

Sting str=new String(“abc”);

这种new 出来的对象会创建在常量池中创建一个字符串对象,复制到堆中,具体的过程是先将常量池压入栈中,在使用String 的构造方法时,会从栈中的字符串作为构造方法的参数,这个构造函数是一个 char 数组的赋值过程,而不是 new 出来的,所以是引用了常量池中的字符串对象。存在引用关系。
在这里插入图片描述

在这里插入图片描述

intern

String 的 intern 方法,如果常量池中有相同值,就会重复使用该对象,返回对象引用。

课堂疑问:

我问:老师您好,昨天你讲的课我有点问题就是,你是新建个String A=“abc” ,String B=“abc”, 如果发现A和B的内容相等就会直接引用到同一个地方,那是不是相当于每次新建一个字符串都会遍历一次字符串常量池?这样设计会不会有影响性能?
老师答:所以这个区域的内存单独设计,同时大小控制,对应的查询遍历算法针对性优化即可。
这个就是为什么要设计这块区域,效率一般还是很高。
你要考虑到对象查找的效率,如果不这么设计,那么每次都要去堆找,堆空间很大,一样效率低

作业

在这里插入图片描述

在这里插入图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值