秋招准备--java

秋招准备之——Java虚拟机 前段时间看了周志明老师的《深入理解Java虚拟机》,加上自己在看的过程中查找的一些资料和理解,做了一些笔记,今天乘着复习,在这里分享一下。 一、Java内存区域与内存溢出异常 1.运行时数据区域 1.程序计数器: 当前线程所执行字节码的行号指示器,线程私有 2.虚拟机栈: 描述方法执行的线程内存模型,每个方法执行的时候,会同步创建一个帧栈存储局部变量等信息。与方法中的局部变量紧密相关,局部变量会存放在局部变量表中,在编译期间,局部变量表所需的空间就确定了。局部变量中的存储空间以局部变量槽表示,long和 阅读详情

秋招准备–java


关于java,也不知道现在秋招有多卷,唉

Java工程师

java常量池

java常量池

  • class文件常量池

    存放字面量和符号引用
    
    字面量即文本字符串与final修饰的变量
    
    符号引用则包括
        类和接口的全限定名,也就是如java/lang/String;
        字段(变量)的名称和描述符
        方法中的名称和描述符
        
    描述符即数据类型、方法的参数列表和返回值
    
  • 运行时常量池

    在方法区
    class常量池加载到运行时常量池
    会让class常量池相同的字符串只留下一份
    动态性,即还可以在运行时修改,如String.intern(),不过JDK1.8里应该是去堆里找
    
  • 全局字符串常量池

    JDK1.6及之前在方法区,存的实例
    JDK1.7方法区只存引用,对象在堆中
    JDK1.8在堆中,而且也只存引用
    字面量会在运行时常量池
    本质是个Hash表
    
String s1 = "Hello";
String s2 = "Hello";
String s3 = "Hel" + "lo";
String s4 = "Hel" + new String("lo");
String s5 = new String("Hello");
String s7 = "H";
String s8 = "ello";
String s9 = s7 + s8;

System.out.println(s1 == s2);  // true
System.out.println(s1 == s3);  // true
System.out.println(s1 == s4);  // false
System.out.println(s1 == s5);  // false
System.out.println(s1 == s9);  // false
  • 包装类常量池

    对于5种整型包装对象(包括BOOlean),-128到127对象在常量池里
    

关于Integer

-128到127对象在常量池里

由于Integer的value是final,所以对Integer对象的修改都是新建Integer对象

关于字符串相加

“a”+“b"会被编译成"ab”,而变量相加则会变成new StringBuilder().append(),所以循环中变量拼接建议手动,不然会不断new

还有就是String.contact(),本质是创建一个放得下两个字符串的数组,再把字符串放到数组里,再转化成字符串,在拼接两个字符串快于builder,大量时则慢

反射运用场景

JDBC,XML配置,面向切面

强引用、软引用、弱引用、虚引用

    强引用指向的对象不会被垃圾回收
    软引用指向的对象在内存超限制时,会被回收
    弱引用只要被垃圾回收扫描到就会被回收,由于垃圾回收优先级低,所以会有一定存活时间
    虚引用相当于没有引用,主要用于跟踪对象被垃圾回收的状态,虚引用不能单独使用,必须和引用队列联合使用。
String str=new String("abc");                                     // 强引用
SoftReference<String> softRef=new SoftReference<String>(str);     // 软引用
WeakReference<String> abcWeakRef = new WeakReference<String>(str);// 弱引用
str=null;//有强引用那么软引用求不起效果,同理,另外string不能常量赋值,不然会在常量池里有引用

关于Map

步步深入的解释

包含同步的详细分析

BlockingQueue

多线程下的队列

先进先出,先进后出
分种类有基于数组,基于链表,延时队列(放入一定时间后才能读,维护超时链接),优先队列,无缓冲队列
ArrayBlockingQueue,LinkedBlockingQueue,DelayQueue,PriorityBlockingQueue,SynchronousQueue

Stream

Stream

用类似sql语言的方法处理集合数据

一个流式处理可以分为三个部分:转换成流、中间操作、终端操作。
  
转换操作:把对象转换成流对象,比如调用.stream()串行,parallelStream()并行

中间操作:对数据处理
  过滤:filter、distinct、limit、skip
       filter指定谓词,比如num->num>10,参数为Predicate
       distnct去重,limit限制数量,skip跳过前n个
  排序:sorted,参数为Comparator
  操作:peek可以对每个选出来的数据操作
  映射:map,类似select
       flatMap,扁平化流,即把所有流的每个值转化成流,再合并成一个流

终端操作:实现对流查找、归约等操作
    查找:allMatch,全部满足则返回true;anyMatch只要有一个;noneMatch一个都不满足
        findFirst获得第一个,findAny返回任意一个,对于串行流两者是一样的
    归约:sum求和,foreach对所有元素执行操作
         reduce,比如reduce(初始值,(a,b)->statement),对于并行的还有参数合并器
        collect收集数据,参数为Collectors.toList,toSet,toMap等,
        还可以.groupingBy实现分组和多级分组,partitioningBy分成false和true的两块区域

另外,可以把流转化为迭代器,还有Spliterator支持并行迭代
public class Main {

  public static void main(String[] args) throws IOException {

    class Item {
      int val;

      public Item(int val) {
        this.val = val;
      }
    }
    List<Item> lt = new ArrayList<Item>() {
      {
        add(new Item(0));
        add(new Item(4));
        add(new Item(1));
        add(new Item(3));
        add(new Item(2));
        add(new Item(2));
      }
    };
    
    //下面按照方法调用顺序执行,顺序不同结果不同
    List<Integer> search=lt.stream().filter(item->item.val>=1).distinct().skip(1).limit(2).sorted(Comparator.comparingInt(a -> a.val))
            .map(item -> item.val).collect(Collectors.toList());
    
    int sum = search.stream().reduce(1, (a, b) -> a + b);

    //直接被分成了六个线程,为1*5*2*4*3*3=360
    int par=lt.parallelStream().map(Item::getVal).reduce(1,(a,b)->a+b,(a,b)->a*b);

    System.out.println(search);//[1, 3]
    
    System.out.println(sum);//5
    
    System.out.println(par);//360

    lt.stream().peek(item->item.val++).filter(item->item.val>1).forEach(item->item.val++);
    for(Item item:lt)
      System.out.print(item.val+" ");//1 6 3 5 4 4 


  }
}
有状态和无状态
有状态 有状态就是有数据存储功能,线程不安全
无状态 无状态就是一次操作,不能保存数据。线程安全
有状态的有distinct,sorted,limit,skip。无状态的有filter,map,peek,unordered等。

短路和非短路
短路的操作有anyMatch,allMatch,findAny,findFIrst,noneMatch ,
非短路的操作有max,min,count,collect,reduce,toArray,forEach,forEachOrdered。

java NIO

同步非阻塞IO

NIO的部分

包含Selector

img.png

Java NIO 系统的核心在于:通道(Channel)和缓冲区(Buffer)与Selector(选择区)
Channel 负责传输,Buffer 负责存储,数据可以从Channel读到Buffer中,也可以从Buffer写到Channel中
Selector用于监听多个通道的事件(比如:连接打开,数据到达)。因此,单个线程可以监听多个数据通道。


Buffer可以当做缓存数组,不过提供了一些特殊的方法,IO的核心在于Channel
Buffer包括四个重要属性:
  position读或写的位置指针
  limit读或写的上限,写时等于capacity,读时为写的了多少
  capacity容量
  mark记录一个position,reset时就reset到这

Channel实现类包括FileChannel,SocketChannel,ServerSocketChannel,DatagramChannel
而如FileInputStream,Socket也有getChannel的方法
支持分散读取与聚集写入(按顺序填满多个Buffer,与多个Buffer按顺序写入Channel)

Selector用于监听channel
让channel调用方法(register)记住selector,当有输入时就会通知channel,这是一种设计模式的运用
无输入返回0,有则可以获取一个列表    
//粘贴
public static void test4() throws Exception {
    RandomAccessFile raf = new RandomAccessFile("a.txt", "rw");
    // 获取通道
    FileChannel channel = raf.getChannel();
    // 分配指定大小缓冲区
    ByteBuffer buf1 = ByteBuffer.allocate(2);
    ByteBuffer buf2 = ByteBuffer.allocate(1024);
    // 分散读取
    ByteBuffer[] bufs = {buf1, buf2};
    channel.read(bufs);  // 参数需要一个数组
    for (ByteBuffer byteBuffer : bufs) {
        byteBuffer.flip();  // 切换到读模式
    }
    System.out.println(new String(bufs[0].array(), 0, bufs[0].limit()));  // 打印 he
    System.out.println(new String(bufs[1].array(), 0, bufs[1].limit()));  // 打印 llo

    // 聚集写入
    RandomAccessFile raf2 = new RandomAccessFile("e.txt","rw");
    // 获取通道
    FileChannel channel2 = raf2.getChannel();
    channel2.write(bufs);  // 把 bufs 里面的几个缓冲区聚集到 channel2 这个通道中,聚集到通道中,也就是到了 e.txt 文件中
    channel2.close();
}
//Selector涉及的代码比较多,以后有空再看

关于多线程

Callable

由于有返回值,所以需要Future对象包装一下负责管理返回值,除此之外Future还能监听线程执行状态
,可以看到FutureTask类有run方法

Thread

.join则让某线程等待该线程执行,.setDameon设置守护线程,除了低优先度,还随主线程结束而结束
,.interrupt等,发出中断信号,线程根据情况处理(中断,继续等),yield运行变就绪,sleep不会放锁

util.concurrent.atomic

原子变量,操作都是原子的,原理为CAS

线程间通讯

  object.wait,Condition.await,BlockingQueue
  关于obj,上锁和通信要基于同一Obj
  关于lock,上锁要基于同一lock,通讯要基于同一condition
  另外,notify会导致释放锁,而singal不会

synchronized与Lock的区别

前者在jvm层面实现锁,后者在代码层面实现锁
前者可以写在代码块上,方法上,后者只能写在代码里
前者自动放锁,后者需要手动,所以要写在finally里
前者线程可能一直等待,后者可以设置超时时间
前者无法知道是否获取成功,后者可以通过tryLock得知(非阻塞,失败返回false,可设置等待时间)
前者锁可重入,不可中断,非公平,后者锁可重入、可中断、可公平/不公平,并可以细分读写锁以提高效率

锁可重入指可重复获取锁,不可中断指的是在等待锁的时候不能被Thread.interrupt
rlock可中断是方法lockInterruptibly(),它会使等待时收到中断信息后停止等待
公平锁按先后,非公平按抢
读写锁,其中写锁会看有没有占用读/写锁,有则停;而读则只看写锁的占用
public class Main{
    public static void main(String args[]){
      muti t1=new muti(0,0);
      muti t2=new muti(100,1);
      new Thread(t1).start();
      new Thread(t2).start();
    }
}
class muti implements Runnable{

    public static volatile AtomicInteger val=new AtomicInteger(0);
    public static ReentrantLock lock=new ReentrantLock();
    public static Condition cd=lock.newCondition();
    public static ReentrantReadWriteLock rwlock=new ReentrantReadWriteLock();
    public int eq;
    public int tid;
    public muti(int i,int tid){ this.eq=i; this.tid=tid;}
    public void run(){

        synchronized (val){
            try {
                System.out.println("线程" + tid + "开始");

                if(tid==0)
                    val.wait();
                else
                    val.notify();//这个会释放锁,如果是new Object().notify(),就会退出这里执行后面的

                System.out.println("线程" + tid + "结束");
            }catch (Exception e){}
        }



         try {
             lock.lock();

             System.out.println("线程" + tid + "开始");
             if(tid==0)
                 cd.await();
             else
                 cd.signal();//这里不会释放锁
             System.out.println("线程" + tid + "结束");
         }catch (Exception e){}finally {
             lock.unlock();
         }

        if(tid==0){
            try{
                rwlock.readLock().lock();
                System.out.println("读1");
                Thread.sleep(1000);
                System.out.println("读1");
            }catch (Exception e){}finally {
                rwlock.readLock().unlock();
            }
        }else{
            
            try{
                rwlock.writeLock().lock();
                System.out.println("写1");
                Thread.sleep(1000);
                System.out.println("写1");
            }catch (Exception e){}finally {
                rwlock.writeLock().unlock();
            }
        }

    };
}

synchronized底层

synchronized底层

在jvm里,对象在内存中分三块:对象头,实例数据,对齐填充
其中对象头包括Mark word,类型指针,数组长度(如果是数组)
其中Mark word存的运行时数据,包括hashcode,锁状态,持有的锁等

当加锁时,就让锁对象的Mark Word里所信息指向对应的线程

作用在代码块时,是让锁对象作位监视器锁monitor(每一个Java对象都有成为Monitor的潜质),
对应的指令是monitorenter(尝试占用monitor)与monitorexit,后者会出现两次

作用在方法时,通过判断是否有标志位ACC_SYNCHRONIZED,有的话则去争取monitor对象

自适应自旋锁:自旋一定次数后都无法获取则挂起,自旋的次数不是固定的,而是由前一次在同一个锁上的自旋时间及锁的拥有者的状态来决定。
锁消除:jvm编译时扫描上下文,去除没必要的锁
锁粗化:把连续加锁解锁操作连接在一起,形成一个范围更大的锁

锁的等级:无锁,偏向锁,轻量级锁,重量级锁(只升级不降级)
偏向锁:一个线程持有对象后,对象进入偏向模式,并记住该线程id,当同一线程再进入,对比id,就不许要申请锁,减少时间开销
轻量级锁:获取偏向锁失败,即出现了多个线程,则Mark word变成轻量级锁结构,并在线程的栈帧中创建一个锁记录,
        用CAS的方式让Mark word的锁指针指向这个拷贝,失败则自旋,自旋失败则阻塞,并升级为重量级锁
重量级锁:线程阻塞

ReentrantLock底层

RenntrantLock底层

CAS+AQS队列

关于AQS
  功能分独占锁和共享锁(允许多个线程同时获取锁)
  维护一个等待的FIFO队列(双向),当线程尝试CAS的形式获取锁失败后,加入FIFO队列并等待
  当锁被释放,则队首的线程被唤醒,尝试获取锁,当为非公平锁,则可能被其他刚好申请锁的线程占领
  当为公平锁,则新线程只会被加到队尾

  有一个state变量,大于1代表被占用,即有锁
  ReentrantReadWriteLock在使用时,稍微有些不同,int型state用二进制表示是32位,前16位(高位)表示为读锁,后面的16位(低位)表示为写锁

  另外还有一个单向的条件队列,被唤醒后会加入FIFO队列队尾

内部类FairSync(公平锁)和NonFairSync(非公平锁)

LongAdder

LongAdder

高并发下计数,atomic的性能变低

LongAdder是在发现竞争时,把数写入一个数组里的一个cell里,最后求和,是空间换时间的思想

Concurrent包

包括atomic,locks(Reentrantlock,AQS,Condition等),线程池Executors,阻塞队列BlockingQueque,并发map,同步器(协助线程同步,FutureTask等)

ThreadLocal

  • 记录线程本地数据,并且不让其他线程修改数据

    可以理解成每个线程都有自己专属的存储容器

    可以用来储存JDBC连接,或者管理对话Session

  • 本质类似HashMap,key为弱引用,这样在强引用没后ThreadLocal好被回收

    这里比较鬼畜,Entry是继承了WeakReference<ThreadLocal<?>>的类,但不代表它是ThreadLocal的子类,而是代表它有一个refernce指向这个ThreadLocal,所以认为Key是弱引用,而不是Entry是弱引用

    然后是为啥设置为弱引用,因为每个线程都有ThreadMap,而ThreadLocal被删了的话,在map仍然存在时,key仍然指向ThreadLocal,导致ThreadLocal不会被回收,所以只有设置为弱引用

  • 内存泄露问题

    比如一个ThreadLocal使用完了,它被设置为null了,按照上面所说,Key也变null了,但是value还在,并且后面删不了,导致内存泄露,所以一个ThreadLocal用完了要记得先把map的remove方法都调用一遍(说到底是弱引用的锅)

  • 关于hash

    ThreadMap的hash,遇到冲突就查找下一个位置,所以ThreadLocal最好设置地少点

public class ThreadLocalTest02 {

    public static void main(String[] args) {

        ThreadLocal<String> local = new ThreadLocal<>();

        IntStream.range(0, 10).forEach(i -> new Thread(() -> {
            local.set(Thread.currentThread().getName() + ":" + i);
            System.out.println("线程:" + Thread.currentThread().getName() + ",local:" + local.get());
        }).start());
    }
}

//输出结果:
//线程:Thread-0,local:Thread-0:0
//线程:Thread-1,local:Thread-1:1
//线程:Thread-2,local:Thread-2:2
//线程:Thread-3,local:Thread-3:3
//线程:Thread-4,local:Thread-4:4
//线程:Thread-5,local:Thread-5:5
//线程:Thread-6,local:Thread-6:6
//线程:Thread-7,local:Thread-7:7
//线程:Thread-8,local:Thread-8:8
//线程:Thread-9,local:Thread-9:9

public class test{
    public static void main(String args[]){
      class A{
        public int a;
        public A(int a){this.a=a;}
        public int get(){return a;}
      }

      class We extends WeakReference<A>{
        public int b=0;

        public We(A referent) {
          super(referent);
        }

        public We(A referent,int i){
          super(referent);
          this.b=i;
        }

      }

      A a=new A(1);
      We we=new We(a,2);
      a=null;
      System.gc();

      try{
        Thread.sleep(1000);
      }catch (Exception e){}

      System.out.println(we.b);//2
      System.out.println(we.get().a);//报空指针错误
    }
}

线程池原理

线程池状态变化

Running,运行状态,可接受新任务,可处理阻塞队列里的任务,调用shutdown方法进入SHUTDOWN,调用shutdownNow进入STOP

SHUTDOWN,待关闭状态,不接受新任务,继续处理阻塞队列,队列空后且工作线程数为0是进入TIDYING状态

STOP,停止状态,不接受新任务和处理阻塞队列,并尝试结束执行中任务,0->SHUTDOWN

TIDYING,整理状态,执行terminated后进入TERMINATED状态

TERMINATED,终止状态,所有资源已释放

重要属性
线程池状态(如上)与工作线程数:被储存到一个atomicInteger里,前3位状态,后29位数量

corePoolSize(核心工作线程数):当向线程池提交一个任务时,若线程池已创建的线程数小于corePoolSize,即便此时存在空闲线程,
也会通过创建一个新线程来执行该任务,直到已创建的线程数大于或等于corePoolSize时。

maximumPoolSize(最大线程数):线程池所允许的最大线程个数。当队列满了,且已创建的线程数小于maximumPoolSize,
则线程池会创建新的线程来执行任务。另外,对于无界队列,可忽略该参数。

keepAliveTime(多余线程存活时间):当线程池中线程数大于核心线程数时,线程的空闲时间如果超过线程存活时间,
那么这个线程就会被销毁,直到线程池中的线程数小于等于核心线程数。

workQueue(队列):用于传输和保存等待执行任务的阻塞队列。

threadFactory(线程创建工厂):用于创建新线程。threadFactory创建的线程也是采用new Thread()方式,
threadFactory创建的线程名都具有统一的风格:pool-m-thread-n(m为线程池的编号,n为线程池内的线程编号)。

handler(拒绝策略):当线程池和队列都满了,再加入线程会执行此策略

线程池的拒绝策略(当达到最大线程数时):
  AbortPolicy:丢弃任务并抛出RejectedExecutionException异常。

  DiscardPolicy:也是丢弃任务,但是不抛出异常。
  
  DiscardOldestPolicy:丢弃队列最前面的任务,然后重新尝试执行任务(重复该过程)。
  
  CallerRunsPolicy:由调用线程处理该任务。

线程池大小设置
    CPU密集型:CPU核心数+1,由于CPU使用率高,避免CPU过度切换
    IO密集型:核心数*2,可以在等待IO时切换到其他线程,提高CPU使用率
    混合型:可以考虑分类成IO与CPU型任务,用不同的线程池处理;但如果拆分后执行时间差距大,则没有意义,不如不拆分

JVM

未完待续

在JDK8,是无法GC方法区

jvm启动过程
    jvm装入环境和配置:java.exe按顺序找JRE(本目录->父目录->注册表)
    装载jvm:找到JRE路径后,通过LoadJavaVM装入JVM文件....
    初始化JVM,获得本地调用接口
    运行java程序:对于class文件,直接调用javac的LoadClass状态类,对于jar包,先调用函数获取主类,再按class文件处理

ClassLoader:分三类
  BootStrap~,负责加载核心类库,C++编写,嵌入JVM内核
  Extension~,负责加载Java扩展类库
  APP~,加载引用程序classpath下的所有jar和class
  另外可根据自身需要自定义的ClassLoader

类加载执行顺序
1、加载:寻找并导入Class文件的二进制信息
2、连接:进行验证、准备和解析
  1)验证:确保导入类型的正确性
  2)准备:为类型分配内存并初始化为默认值(静态变量)
  3)解析:将字符引用解析为直接引用
3、初始化:调用Java代码,初始化类变量为指定初始值

方法区
类信息,运行时常量池等
包括方法编译出的字节码

Java栈与本地方法栈
  Java栈里只存基础类型的数据和对象的引用
  本地栈是存native方法的栈(它们不由java编写,所以不是管理jvm运行)

堆和GC

JVM对堆采用了分代算法,年轻代用赋值算法,老年代采用标记整理算法(用于GC)

  • 年轻代:主要存放新创建的对象,内存较小,GC较频繁,分为伊甸园和两个(from,to)幸存者区

    • 产生新对象会先放在伊甸园,如果空间不够则会发生young GC
    • young gc流程:扫描伊甸园和from区,如果对象存活,则把其复制到to区,to区满则复制到老年代,然后清空伊甸园和from区,最后交换from,to区的角色
    • 在幸存者区的对象有年龄计数器,每通过一次GC就+1,达到一定次数(默认15,可设置)就进入老年代
  • 老年代:用于存放生命周期长的对象

    • 当young gc后对象进入老年代,但老年代空间不够,就会发生majorGC;或者无法找到足够大的连续空间创建较大对象时也会提前触发一次old GC。老年代也装不下时会触发OOM异常
    • old GC:标志整理算法:先扫描一次标记出存活对象,再回收没有标记的对象,由于会产生内存碎片,所以会把所有存活对象向一段移动,再清除边界以外的内存(另外还有不好用的标记复制,标记清除)。
  • 永生代:内存上跟在堆后面,在JAVA8里已没有,被替换为元空间

  • GC

    • 判断对象回收条件:没有引用/作用域发生未捕获异常/作用域正常执行完毕/执行System.exit()/程序意外终止
    • Full GC,没有官方的定义,大众认知上为回收整个堆的空间可被回收的对象
    • stop the world:在运行到安全点后,挂起,然后gc
    • 根搜索算法:从一系列GC Roots的对象出发走引用链,没被走到的对象则可回收
  • 其他

    • 新生代和老年代各有对应的几种收集器

元空间

与永生代的区别:不再用虚拟机设置的内存,而是用本地内存(这里指的是堆外内存);并且字符串常量和静态变量在堆中,不在元空间里

与方法区的关系:以前的方法区的实现是永生代,现在的是元空间

程序计数器

当执行到native方法时,计数器为空

本地方法接口

实现Java程序与其他语言库、硬件、操作系统的交互,缺点是不再跨平台和安全

关于实例化

顺序是静态变量->静态代码块->变量->代码块->构造器

包含父类下则是父类静态->子类静态->父类非静态->子类非静态->父类构造器->子类构造器

双亲委派模型

要求除了根加载器每个加载器都要有父类,当要加载一个类时,首先尝试把任务委托给父类,如果父类不行,则尝试当前类加载

内存泄露和内存溢出

内存泄露的根本源因是长生命周期对象持有不被需要的短生命周期的引用,分4中
常发性~/偶发性/一次性:导致内存泄露的代码执行多次/少次/一次
隐式内存泄露:内存的释放被拖到程序结束时或者很久后,尽管早就没有用了

内存溢出:申请内存大于可用内存

垃圾回收器与一些参数

名称解释分类
Serial最早的单线程串行垃圾回收器年轻代
Serial OldSerial的老年代版本,标记整理老年代
ParNewSerial的多线程版本年轻代
Parallel多线程吞吐量优先的收集器(牺牲等待时间)年轻代
Parallel Old老年代版本,标记整理老年代
CMS以获取最短停顿时间为目标的收集器,适合B/S,基于标记清除算法,写屏障 + 增量更新老年代
G1兼顾等待时间和吞吐量,JDK9后的默认GC选项,写屏障 + SATB整堆

三色标记和读写屏障

三色标记法:从GCroot出发,默认白色,访问到该节点,但所有子节点未访问完为灰色,访问完则变黑色
如果是stop the world,不会出现什么问题,而如果要支持应用程序代码的并行,则会出现两种问题
  多标-浮动垃圾:
    比如访问到对象(灰色)后,把引用链断了,那么这个对象该被回收,但这次不会被回收。不过在下一次会被回收
    对于新对象,直接标为黑色,就不会在本轮被清楚,虽然可能期间垃圾
  漏标-读写屏障:
    就是比如黑色D指向灰色E,E指向白色G,此时(1)读并(2)断开E->G,(3)连接D->G,那么G就不该被清除,但它已经无法被标色了,三个条件破坏任意一个就行
    写屏障+SATB(针对2):把要改变的引用对象记录下来,相当于是保存了以前链接关系的快照
    写屏障+增量更新(针对3):记录新的引用对象,让GC在后面访问
    读屏障(针对1):即读取时就把引用对象记录下来,相当于增量版写屏障+SATB

默认空间老年代:新生代2:1,默认新生代中伊甸园和幸存者区比例8:1:1

JVM调优参数:-Xms 堆内存起始大小;-Xmx 最大的堆内存;-Xmn 新生代大小;-XX:SurviviorRatio:n 伊甸园与幸存者区的比例n:10-n…

跳过部分

编译过程,class加载详细过程,等等等等,感觉已经不是应届生该看的了,暂时跳过

暂时完结

2022Java基础、语法最全面试题,为秋招做好准备 1.Java跨平台原理(字节码文件、虚拟机)C/C++语言都直接编译成针对特定平台机器码。如果要跨平台,需要使用相应的编译器重新编译。Java源程序(.java)要先编译成与平台无关的字节码文件(.class),然后字节码文件再解释成机器码运行。解释是通过Java虚拟机来执行的。字节码文件不面向任何具体平台,只面向虚拟机。Java虚拟机是可运行Java字节码文件的虚拟计算机。不同平台的虚拟机是不同的,但它们都提供了相同的接口。Java语言具有一次编译,到处运行的特点。就是说编译后的.class可以跨平台运行 阅读详情

相关推荐

妥妥的精华之Java工程师秋招回忆录+面经汇总,为了拿BAT的研发offer我都做了那些准备

秋招总结 写在最前 我写过很多篇秋招总结,这篇文章应该是最后一篇总结,当然也是最完整,最详细的一篇总结。秋招是我人生中一段宝贵的经历,不仅是我研究生生涯交出的一份答卷,也是未来职业生涯的开端。仅以此文,献给自己,以及各位在求职路上的,或者是已经经历过校招的朋友们。不忘初心,方得始终。 前言 在下本是跨专业渣考研的985渣硕一枚,经历研究生两年的学习积累,有幸于2019秋季招聘中拿到几个公司的研发岗offer,包括百度,阿里,腾讯,今日头条,网易,华为等。 (在秋招末期,有幸又拿到了滴滴和亚马逊的o

qq_64513388的博客 875

程序员秋招最全Java面试题及答案整理(2023最新版)

大家好,最近一个月,花了不少时间,给大家整理了一套 2023 的技术面试资料包括各大厂最新面试题以及面经解析涉及JVM,Mysql,并发,Spring,Mybatis,Redis,RocketMQ,Kafka,Zookeeper,Netty,Dubbo,ElasticSearch,Flink,Spring Boot,Spring Cloud,高并发项目,大数据系列,数据结构与算法,设计模式,网络与操作系统等20个技术栈的大厂面试题及详解文档(接近2000页)。具体包含哪些内容,请往下看。

qq13321123的博客 1835

双非本科准备秋招(4)——力扣链表与java基础

java操作链表的时候要比c++方便一些,因为c++需要自己手动释放资源,而jvm虚拟机具有垃圾回收机制(GC),如果这个对象将来没被引用过,就会自动回收其所占用的内存。LeetCode上的链表结构不是定义的集合形式,而是结点形式,什么意思呢,举个例子。这种就属于集合的方式定义链表,在里面定义内部类Node节点对象,如果需要使用,只需要创建链表对象,调用其中的方法。LeetCode上的相当于把Node节点类直接拿出来,用头节点代表整个链表。

qq_62726880的博客 1176

Java后端秋招如何准备?

Java后端秋招如何准备?

weixin_41171614的博客 1691

秋招总结:花了半年时间,准备Java后端开发工程师的面试,最终让我收获了8个大厂offer

Persist,and anything is within your reach. 坚持下来,做任何事情你都能成功。 关注再看,养成习惯,大家好,我是程序哥!微信搜索【VeryJava】关注一下,这很Java。本文 GitHub https://github.com/clsaa/very-java 已收录,整理了本人面试过程学习的知识,正在逐步开放,欢迎Star和Fork。 绪论 想写这篇文章,已经很久了,之前在准备秋招的时候,就一直想着如果我能顺利拿到offer,一定也写一篇博客总结一下。毕.

JAVA程序哥 2262

时序分析-由D触发器结构来理解Tsu、Th

FPGA逻辑单元内的D触发器(D-FF)是一种在时钟的上升沿(或下降沿)将输入信号的变化传送至输出的边沿触发器。 数字电子技术基础-闫石(第五版)边沿D触发器内部结构见下图: 而FPGA原理与结构(日)一书中,内部结构较之上图多了俩反相器: 由传输门和俩个反相器组成一个循环电路(锁存器),再由前后两级锁存器按主从结构链接而成。这里的传输门起开关作用,随着CLK的状态变化切换开关。只看输出的话,前级锁存器的值会随着时钟输入的变化井然有序地传入后级锁存器。为了防止时钟信号变化时输入信号发生冒险,从而使稳定.

XY_Chang的博客 3973

秋招指南(菜狗版)-Java前/后端开发方向

期末考试结束,菜的人还在享受假期,即将进大厂的已经在学习了(狗头)作为经受去年秋招摧残的老学姐,给大家带来一些秋招学习的小经验,希望可以帮助大家避免一些求职路上的坑,能快速顺利地找到心仪的工作。本文总共分为心态篇、时机篇、简历篇、学习路径篇。

LYly_B的博客 5723

LSM6DSOW陀螺仪轮询驱动:从I2C/SPI配置到数据读取全解析

惯性测量单元(IMU)是现代嵌入式系统中实现姿态感知与运动跟踪的核心传感器,其通过加速度计和陀螺仪测量线性加速度与角速度。在嵌入式开发中,轮询(Polling)作为一种基础且可靠的通信方式,通过主循环主动查询传感器状态,简化了初始调试与验证流程。对于I2C/SPI接口的数字传感器,掌握寄存器配置、数据就绪标志检查及原始数据转换是通用的驱动方法,能够快速验证传感器工作状态并理解数据流。LSM6DSOW作为一款高性能6轴IMU,支持可配置的量程与输出数据速率,适用于无人机飞控、手持云台等高动态场景。本文以LSM

weixin_28728265的博客 557

2023秋招,Java岗最全面试攻略,吃透25个技术栈Offer拿到手软

我分享的这份秋招 Java 后端开发面试总结包含了 JavaOOP、Java 集合容器、Java 异常、并发编程、Java 反射、Java 序列化、JVM、Redis、Spring MVC、MyBatis、MySQL 数据库、消息中间件 MQ、Dubbo、Linux、ZooKeeper、 分布式 &数据结构与算法等 25 个专题技术点,都是小编在各个大厂总结出来的面试真题,已经有很多粉丝靠这份 PDF 拿下众多大厂的 offer,今天在这里总结分享给到大家!

m0_50180963的博客 433

手把手教你用FreeModbus RTU协议栈实现STM32与PLC通信(附Keil工程)

本文详细介绍了如何使用FreeModbus RTU协议栈在STM32上实现与PLC的工业通信。从环境搭建、工程配置到关键移植接口实现,提供了Keil工程模板和调试技巧,帮助开发者快速掌握Modbus RTU通信技术,适用于工业自动化领域的设备间通信需求。

weixin_42549037的博客 419

为R720安装iDRAC Service Module

这玩意找了好久资料, 教程都不咋靠谱, 要不就是有不理解的地方 所以直接一路莽着过河: 去官网找到设备对应的驱动程序: 几个查找筛选项看图 官网链接: https://www.dell.com/support/home/zh-cn/product-support/product/poweredge-r720/drivers 在下方的列表中找到对应系统版本的驱动并下载: 由于安装的系统为ESXi 6.5 U2 Dell定制版, 这里没有刚好的驱动, 所以下了个兼容的: 下载好后是一个压缩包:

Janus 6361

2022秋招,Java岗最全面试攻略,吃透25个技术栈Offer拿到手软

我分享的这份秋招 Java 后端开发面试总结包含了 JavaOOP、Java 集合容器、Java 异常、并发编程、Java 反射、Java 序列化、JVM、Redis、Spring MVC、MyBatis、MySQL 数据库、消息中间件 MQ、Dubbo、Linux、ZooKeeper、 分布式 &数据结构与算法等 25 个专题技术点,都是小编在各个大厂总结出来的面试真题,已经有很多粉丝靠这份 PDF 拿下众多大厂的 offer,今天在这里总结分享给到大家!我这篇分享篇幅可能有点长,观看的朋友可以先了解一下

aa119101的博客 426

从VASP数据到LAMMPS模拟:手把手教你用DeePMD-kit搭建Cr-Si-Fe合金势函数

本文详细介绍了使用DeePMD-kit从VASP数据构建Cr-Si-Fe合金深度势能模型的全流程,包括数据准备、模型训练、优化及LAMMPS集成。通过实战教程,帮助研究者掌握DeePMD-kit训练技巧,实现高精度分子动力学模拟,提升材料计算效率。

weixin_33737134的博客 521

7月末才开始准备秋招还有机会嘛?(java后端岗,做过几个小项目,水平停留在增删改查)

立即开始,聚焦核心,避免完美主义。统计显示,准备秋招的学生中,80%的失败源于拖延或方向错误。你的项目经验是起点,现在强化算法和系统设计,就能显著提升竞争力。如果需要更具体的资源列表或学习计划,可以进一步讨论。加油,秋招路上,每一步都算数!

程序员高级码农的博客 1393

RH850从0搭建Autosar开发环境【2】- Davinci Configurator配置工程导入DBC与CDD文件

Davinci Configurator配置工程导入DBC与CDD文件,开始Autosar开发

weixin_42412049的博客 8153

解锁IPG Photonics SmartWeld系统,开启焊接新时代

SmartWeld 系统是 IPG Photonics 研发的一款先进的激光焊接解决方案,它隶属于自动化激光焊接系统类别 ,但却凭借一系列创新技术和独特设计,在众多同类产品中脱颖而出。该系统基于 IPG 在光纤激光技术领域的深厚积累,融合了先进的光束控制、智能监测和自动化控制等技术,旨在为工业制造提供高效、精准且稳定的焊接工艺。与传统激光焊接系统相比,SmartWeld 系统的独特之处首先体现在其光束控制技术上。它能够精确地调整激光束的能量分布、光斑大小和形状 ,以适应不同材料和焊接工艺的需求。

远程部署调试 运行安装 项目调试 二次开发 项目技术新 持续迭代 部分源码免费分享 1430

临近毕业,如何系统自学Java为秋招拿offer做准备?

秋招马上就要开始了,最后有很多同学私信问我秋招应该如何做准备?由于学生在学校没有机会接触到实际项目,在学习方向,内容,就业的标准方向都不是很明确,现在公司招人的标准越来越高,而大学里面的内容过于基础,且偏重理论,所以学到的往往和公司需要的技术不匹配。很多学生虽然在学校很努力地学习,但是临近毕业,才发现自己所学内容并不能找到一份满意的工作。本文将结合我面试实习生和毕业生的标准,给大家全面的分析一下。

weixin_64403990的博客 210

AXI-5.6 Multiple region interfaces

规则:如果从设备实现的区域少于16个,它必须确保对任何访问未支持区域的尝试都能给出符合协议的响应。具体实现方式由设计者定义。场景:一个错误的软件驱动试图向区域 5(该加密加速器未实现)写入数据。实现方式一:提供错误响应(严格模式)行为:加密加速器检测到AxREGION的值大于2,立即对该事务返回一个DECERR(解码错误)或SLVERR(从设备错误)响应。举例:这类似于你访问一个不存在的网站,服务器返回“404 Not Found”。它明确告知请求者:“你要找的东西不存在”。优点安全、清晰。

weixin_44700185的博客 672

秋招准备之java

java 知识点学习 这时候不建议看书。 java编程思想的代码 Android校招面试指南 · GitBook 在这里看看多态,继承,封装,接口 大佬对java的总结,适合挑着看 里面有好几篇文章与面试有关 没别的意思,就是想看看阿里面试水平 Java 中的异常和处理详解,检查异常有时又称强制异常 面试官问我具体实现/具体场景(具体怎么问的忘了)。 java的序列化 Java 泛型总结 Ja...

dw33xn的博客 700

Devexpress16.2.6破解工具

Devexpress16.2.6破解工具Devexpress16.2.6破解工具Devexpress16.2.6破解工具Devexpress16.2.6破解工具

efm32 入门.pdf

本PDF共计22页,介绍的是操作驱动API,下载与否自己斟酌。

秋招面试准备(一)Java基础

一、面向对象和面向过程 面向对象:易维护、易复用、易拓展。因为“继承、封装、多态”的OOC特性,系统低耦合。 面向过程:性能高。根本原因:Java是半编译语言,需要将.java源代码编译为.class字节码文件,才能在不同机器上的JVM上运行。 二、Java语言的特点 1、面向对象(抽象、继承、封装、多态) 2、平台无关性(JVM) 3、支持多线程(C++11之前,C++需要依赖操作系统的多线程实现多线程) 4、支持网络编程 5、编译和解释共存 三、JDK|JVM|JRE 1、JVM:Java虚拟机,用于运

weixin_48214777的博客 621

文档:亲测可用解决vnc灰屏,黑屏,鼠标大黑叉情况

主要解决vnc-viewer灰屏,黑屏,鼠标大黑叉等现象,详细见文档。

准备参加春招或者准备秋招的Java应届生们看过来了,给你分享一下我得经验

当应届生参加春招、秋招的时候,有些人可鞥在前辈们的灌输下得到醍醐灌顶,但是我觉得像我一样懵懂的小伙伴也不在小数,所以在这里写一篇我自己的个人经历希望能让你们少走弯路。 首先,在简历投递层次上肯定是简历是第一层次,你简历过了筛选之后才能够参加接下来各个公司的笔试、面试。 在简历上对于自身的真实经历书写,如果你在大学期间寒暑假参加过某些对口的培训班、或者在寒暑假中的实习我觉得这是一个非常好的加分项,当然在学校组织的比赛也是很大的加分项(很多时候还得看你想进去那...

weixin_49167478的博客 1087

春招结束,秋招你准备好了吗?(没准备好还不进来看下)Java岗

春招基本已经结束,很多同学都是第一次参加笔试和面试,往往是懵的状态,但是时间不等人,现在距离秋招提前批开始也就两个多月的时间了,要开始准备秋招了,那个时候再没有实力的话就真的会被淘汰啦! 校招的技术栈考察和占比情况为: 笔试占比: **简单分析:**笔试一般是选择题+三道编程题,也有的全是编程题(比如华为,今日头条)等等 可以看到,算法占比是最大的,算法不好的话编程题根本没法做,而且在线oj和本...

weixin_44782075的博客 494

超硬核java工程师秋招,为了BAT的研发offer,做了那些准备?

秋招结束以后,我就把主要精力花在做这个上了。当然,剩下要处理的事情还有很多,毕业论文,毕业旅行,还有工作前的知识储备等等。果然,人的一生需要不断的修行,刚刚闯过了一关又马上要迎接下一轮挑战,你不能停下脚步,毕竟大家都在往前走。...

YYniannian的博客 653

【秋招面试专题解析】面试字节跳动的Java工程师该怎么准备

前言 疫情过去,真正的春暖花开又回来了,时不时的可以和朋友约个饭,感慨今年的工作竞争压力很大,工作很不好找。作为一个开发人员,你是否面上了理想的公司,拿到了理想中的薪资? 作为程序员,跳槽就是最好的涨薪方式。前提当然是你有足够实力,而不是只会纸上谈兵。面试准备不充分,就是浪费时间,更是对自己不负责任。 今天给大家分享一份由粉丝投稿,我精心整理出来的一份1200页Java架构面试专题(文末见面试答案),绝大部分都是一线大厂的面试真题,可以根据这份面试专题查漏补缺,希望能够帮助你尽快找到工作! 1.美团面试官问

m0_56710876的博客 463

2022Java集合最全面试题,为秋招做好准备

193.Java集合体系结构(List、Set、Collection、Map的区别和联系) 1、Collection 接口存储一组不唯一,无序的对象2、List 接口存储一组不唯一,有序(插入顺序)的对象3、Set 接口存储一组唯一,无序的对象4、Map接口存储一组键值对象,提供key到value的映射。Key无序,唯一。value不要求有序,允许重复。(如果只使用key存储,而不使用value,那就是Set)194.Vector和ArrayList的区别和联系相同点:1)实现原理相同---底层都使用数组2

a6636656的博客 305

我是如何准备秋招互联网大厂后端学习的?

写在前面 上周给师弟师妹们分享了我的秋招经验,总结了秋招中的一些问题,于是现在也把这些东西给发在博客上分享出来,毕竟之前也参考了很多其他人的经验,是时候回馈了。 本人末流双9硕,电子信息工程专业,java后端开发,非科班纯靠自学,秋招时刷题300+,基本无竞赛经历,无国奖,纯靠面评。秋招阶段拿了阿里、百度、字节的一些sp和ssp,还有一些其他的offer,就不赘述。整个秋招因为准备充分,基本非常顺利,结束的也非常早。 下面的内容是我从 为分享会做的ppt上复制过来的,为了省事,就不做过多的排版了。本文主观性

或左的博客 3008
上一篇: 山大软工实践hive(14)-总结
meloneatingguy
博客等级 码龄7年 1粉丝 15原创
评论 1
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

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

抵扣说明:

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

余额充值