1.垃圾回收不涉及栈内存,因为栈帧进栈后,方法调用完后,会弹出栈,直到主方法也弹出栈,最后栈就成空的了,所以不用垃圾回收来管理栈内存,垃圾回收主要是回收堆内存中的无用对象;

2.栈的内存并不是越大越好,栈内存越大,意味着线程就越少,因为物理内存大小是一定的,可以通过启动参数-Xss (size)来指定大小;

3.方法内的局部变量的安全,要看局部变量是普通局部变量,还是共享的变量,因为每个线程都有属于自己的栈,每个线程执行时,普通变量都会初始化然后进入栈;但是如果变量前加了static修饰,变成了共享的变量,就可能出现线程安全问题;

4.如果方法内的局部变量没有逃离方法的作用范围,它就是线程安全的;如果局部变量引用了对象,并逃离了方法的作用方法,需要考虑线程安全问题;

5.栈内存溢出(StackOverFlow):
  -1.栈帧过多,导致的内存溢出:例如,使用了递归方法但并没有设置好出口,就会导致栈帧过多;
  -2.栈帧过大;
  
6.JSON对象转换;
  -1.Jackson:
    // 依赖
   // <dependency>
   //     <groupId>com.fasterxml.jackson.core</groupId>
   //     <artifactId>jackson-databind</artifactId>
   // </dependency>

   ObjectMapper mapper = new ObjectMapper();
   // 对象转JSON字符串
   String jsonStr = mapper.writeValueAsString(user);
   // JSON字符串转对象
   User user = mapper.readValue(jsonStr, User.class);
  -2.Fastjson:
    // 依赖
    // <dependency>
     //     <groupId>com.alibaba</groupId>
   //     <artifactId>fastjson</artifactId>
   // </dependency>

   // 对象转JSON
   String jsonStr = JSON.toJSONString(user);
  // JSON转对象
   User user = JSON.parseObject(jsonStr, User.class);
   
7.堆内存溢出(OutOfMemory):
  -1.堆内存可以通过-Xmx(size)参数来控制;
  -2.终端可视化查看指令:jconsole
  
8.方法区:
  -1. jdk1.8以前永久代内存溢出(PermGen space)
  -2. jdk1.8以后元空间内存溢出(Metaspace)
  -3.常量池:常量池就是一张常量表,存储了字面量,符号引用,运行时常量, 虚拟机指令根据这张表找到要执行的类名,方法名,参数类型,字面量等信息;
  -4.运行时常量池:常量池时.class文件中的,当该类被加载,它的常量池信息就会被放入运行时常量池,并把里面的符号地址变为真实地址;
  
9.stringTable(串池):
  -1.hashtablea结构不能扩容
  -2.每创建一个字符串就会往串池里找,如果找到了,就使用串池中的对象,没找到就创建一个字符串对象,并添加到串池中
  -3.如果字符串是两个字符串对象拼接的,就会new出一个新的字符串对象,而不是去串池中找;如果是两个字符串拼接的就会去串池中找;
    例如:string s1="ab";
	    string s2="a"+"b";
		string s3="a";
		string s4="b";
		string s5=s3+s4;  -->相当于new stringbuilder().append("a").append("b").build();
		
		s1==s2 ->true
		s1==s5 ->false
  -4.intern()方法,可以主动将串池中没有的字符串对象放入串池;
     str.intern()会先去串池中找有没有相应的字符串,有的话就返回串池中的对象,没有的话会把字符串放入串池,并返回相应对象;
  -5.垃圾回收
  -6.性能调优:
    --1.通过-XX:StringTableSize=(size)参数来设置桶的大小来提高效率;
	--2.通过intern()方法来将字符串放进串池,来忽略重复的字符串来提高效率;
  -7.哪些字符串会入池,哪些不会:(ai询问答案,此处略)
  
10.直接内存: 不受JVM内存回收管理,需要手使用unsafe对象主动使用freememory才能回收内存;

11.垃圾回收:
  -1.判断垃圾(如何判断一个垃圾是否要回收):
    --1.引用计数法;
	--2.可达性分析算法(java虚拟机使用的):从一组 GC Roots(根) 出发,沿引用链向下搜索,凡是能被 GC Roots 直接或间接引用到的对象都是存活的,否则是垃圾;
	类似于一串葡萄,拿起来能被根连着的不掉下来的就是有用的,没连着的掉下来的就是垃圾,要被回收
	  -1.哪些对象可以作为GC Root对象
	   --1. 虚拟机栈中引用的对象
       局部变量、方法参数等:
       --2. 本地方法栈(JNI)中引用的对象
	   JNI 调用的 native 方法中持有的引用。
	   --3. 方法区中类的静态变量
       static Object obj = new Object();
       obj 是 GC Root
	   --4. 方法区中常量引用的对象
	   例如字符串常量池中的字符串被引用。
	   --5. ClassLoader 持有的对象
	   --6. 运行时的线程对象
	   --7. JVM 内部引用的对象
	   如系统类加载器、线程对象等。
  -2.五种引用:
    --1.强引用:被引用的对象不会被垃圾回收机制回收掉
	--2.软引用:没有强引用的条件下,进行垃圾回收,且内存不足就会被回收掉; 可以配合引用队列来释放软引用自身
	--3.弱引用:没有强引用的条件下,进行垃圾回收,不管内存是否不足都会被回收掉; 可以配合引用队列来释放弱引用自身
	--4.虚引用:虚引用是 java.lang.ref.PhantomReference<T>,它是最“弱”的引用类型。它不会通过 get() 返回所引用的对象(get() 永远返回 null); 必须配合引用队列使用;
	          没有强引用后,引用的对象会被垃圾回收机制回收掉,同时进入引用队列,再将与之关联的直接内存回收
	--5.终结器引用:类似于监控对象的finallize()方法;使用了就回收相应垃圾
  -3.回收算法:
    --1.标记清除:效率高,但是容易内存碎片化;
	--2.标记整理:不会出现内存碎片化,但效率较低
	--3.复制:不会出现内存碎片化,但是会占用双倍内存空间
  -4.分代回收:分代回收就是根据对象的“生命周期长短”把堆划分为年轻代和老年代,并分别采用最适合的回收算法(复制 + 标记整理)来提升 GC 性能;
     --1.新生代分为伊甸园,幸存区from,幸存区to; 对象首先会分配到伊甸园区域,当伊甸园内存不足时,会发生minor Gc按复制的垃圾回收算法进行垃圾回收,伊甸园和幸存区from中存活的对象copy复制到幸存区to中,存活的对象年龄加一;并且幸存区from和幸存区to交换,保证幸存区to是空的;
	    当对象寿命到达一定阈值(最大是15,因为对象头中存储寿命的部分是4bit, 4个二进制最大为15)时就会转移到老年代中;
	 --2.minor Gc会导致stop the world,暂停其他用户的线程,等垃圾回收结束,用户线程才会恢复运行;
	 --3.当老年代空间不足,会先尝试minor Gc,如果空间仍然不足,就会执行full Gc;
  -5.Gc分析:启动时再编辑运行配置中添加虚拟机参数-Xms20M -Xmx20M -Xmn10M -XX:+UseSerialGC -XX:+PrintGCDetails -verbose:gc;要先在编辑配置中,在修改选项里勾选添加虚拟机选项;
  -6.垃圾回收器:
    --1.串行(Serial): -XX:+UseSerialGC=serial+serialOld
	--2.吞吐量优先(Parallel)(并行执行,用户线程能同时运行,但是垃圾回收时还是会STW(stop the world)): -XX:+UseParallelGC//指定新生代使用parallel并行收集器执行内存回收任务;-XX:+UseparallelOldGC//指定老年代使用并行回收收集器
	--3.响应时间优先(CMS)(并行执行,用户线程能同时运行,但是部分垃圾回收阶段还是会STW)CMS 是一种以最小停顿为目标的老年代并发回收器,使用标记-清除算法,但会产生碎片,因此被 G1 替代: -XX:+UseConcMarkSweepGC
	    CMS分为四个阶段:初始标记阶段(会STW),并发标记阶段,重新标记阶段(会STW),并发清除阶段;  <具体每个阶段所作的事,ai搜索学习>
  -7.G1: G1 是 HotSpot JVM 中面向服务端/大内存/低延迟应用的垃圾回收器;G1 不再像 CMS 一样分代 + 连续内存,而是把整个堆拆成多个大小相同的 Region;每个 Region 会动态被当成:Eden,Survivor,Old,Humongous(巨型对象区 > 一半 Region);w
    --1.young GC: 回收 Eden → Survivor,使用 STW + 并行复制
    --2.Mixed GC: 当老年代逐渐增大时,G1会在 Young GC 的基础上额外选取 部分 Old Region(垃圾最多的) 进行回收;
    --3.Full GC: 极端情况(比如 RSet 太大、晋升失败等),会触发 单线程 Full GC(很慢)
    --4.G1 的最大价值是可预测停顿。可以设置:-XX:MaxGCPauseMillis=200; G1 会智能选择:在 200ms 内能回收最多垃圾的Region 集合。如果超过可预测范围 → 调整算法或进入 Full GC。
    --5.young GC跨代引用 <ai搜索学习> :使用写屏障记录“老年代对象引用年轻代”的情况,通过卡表 + RSet,让 Young GC 只扫描少量卡片,不必遍历整个老年代;
    --6.写屏障:用来记录引用关系的变化,以支持并发 GC 或跨代引用处理;GC 过程中,对象之间的引用会不断变化,写屏障负责把这些变化记录下来,帮助 GC 稳定、正确地工作。
  -8.GC调优:
    --1.java终端运行java -XX:+PrintFlagsFinal -version | findstr "GC"可以查看GC相关信息
	--2.新生代内存不足,执行的是minorGC(标记复制算法),会STW,可以适当使用-Xmn虚拟机参数来加大新生代内存,但是并不是新生代内存越多就越好,新生代内存多了,相对老年代内存就少了,而老年代内存不足执行的是FullGC,STW时间会更久;所以一般控制新生代内存占堆的25%~50%;
	--3.新生代晋升到老年代的阈值会根据幸存区内存大小自动调节,如果幸存区内存太小,阈值就会相对较小,容易使得其实应该最终变为垃圾的对象进入老年代,导致占用老年代的内存,只有等到fullGC时才能被回收掉,延长了垃圾存活的时间,这是不好的;所以要尽量使得幸存区内存够大,大到能保留当前活跃对象和需要晋升的对象
	--4.但是又想要长期存活的对象尽快进入老年代,来减少幸存区中from到to的对象,因此又要设置较小的晋升阈值;因此设置一个合理的晋升阈值很重要;-XX:MaxTenuringThreshold=(Threshold)//设置最大晋升阈值 -XX:+PrintTenuringDistribution//打印详细页
	--5.老年代的内存也是越大越好,可以先不调试,记录fullGC时内存的大小,在此基础上适当调大1/4~1/3;
  -9.GC调优案例:
    --1.minorGC和fullGC频繁: 通过检测工具发现新生代内存太小了,幸存区太小,对象晋升阈值小,增大新生代内存,增大幸存区空间,增大幸存区中对象晋升阈值,减少fullGC出现
	--2.(CMS)请求高峰期发生了fullGC,STW时间很长: 查看GC日志,发现在重新标记阶段花费了很多时间,重新标记阶段会扫描整个堆的内存,在请求高峰期,对象较多,耗费时间较长; 使用参数-XX:+CMSScavengeBeforeRemark,在重新标记之前垃圾清理
	
	
12.类加载和字节码技术:
  -1.类文件结构 <ai查询>
  -2.字节码指令
    --1.图解运行流程: 任务:深刻理解 a++ + ++a + a--;
	--2.条件判断指令
	--3.循环控制指令
	--4.多态原理
	--5.异常
	--6.锁
  -3.语法糖:
    --1.默认构造器
	--2.自动拆装箱
	--3.泛型集合取值
  -4.类加载阶段
    --1.加载
	--2.链接
	--3.初始化
  -5.类加载器
  -6.运行期优化
    --1.即时编译
13.JMM(java memory model) java内存模型
   --1.可见性
   --2.有序性
   --3.CAS和原子类