JVM的垃圾回收机制 总结(垃圾收集、回收算法、垃圾回收器)

2023-11-02

如果想了解Java内存模型参考:jvm内存模型-和内存分配以及jdk、jre、jvm是什么关系(阿里,美团,京东)

相信和小编一样的程序猿们在日常工作或面试当中经常会遇到JVM的垃圾回收问题,有没有在夜深人静的时候详细捋一捋JVM垃圾回收机制中的知识点呢?没时间捋也没关系,因为小编接下来会给你捋一捋。

一、 技术背景你要了解吧

  按照套路是要先装装X,谈谈JVM垃圾回收的前世今生的。说起垃圾回收(GC),大部分人都把这项技术当做Java语言的伴生产物。事实上,GC的历史比Java久远,早在1960年Lisp这门语言中就使用了内存动态分配和垃圾回收技术。设计和优化C++这门语言的专家们要长点心啦~~

二、 哪些内存需要回收?

  猿们都知道JVM的内存结构包括五大区域:程序计数器、虚拟机栈、本地方法栈、堆区、方法区。其中程序计数器、虚拟机栈、本地方法栈3个区域随线程而生、随线程而灭,因此这几个区域的内存分配和回收都具备确定性,就不需要过多考虑回收的问题,因为方法结束或者线程结束时,内存自然就跟随着回收了。而Java堆区和方法区则不一样、不一样!(怎么不一样说的朗朗上口),这部分内存的分配和回收是动态的,正是垃圾收集器所需关注的部分。

  垃圾收集器在对堆区和方法区进行回收前,首先要确定这些区域的对象哪些可以被回收,哪些暂时还不能回收,这就要用到判断对象是否存活的算法!(面试官肯定没少问你吧)

2.1 引用计数算法

2.1.1 算法分析

  引用计数是垃圾收集器中的早期策略。在这种方法中,堆中每个对象实例都有一个引用计数。当一个对象被创建时,就将该对象实例分配给一个变量,该变量计数设置为1。当任何其它变量被赋值为这个对象的引用时,计数加1(a = b,则b引用的对象实例的计数器+1),但当一个对象实例的某个引用超过了生命周期或者被设置为一个新值时,对象实例的引用计数器减1。任何引用计数器为0的对象实例可以被当作垃圾收集。当一个对象实例被垃圾收集时,它引用的任何对象实例的引用计数器减1。

2.1.2 优缺点

优点:引用计数收集器可以很快的执行,交织在程序运行中。对程序需要不被长时间打断的实时环境比较有利。

缺点:无法检测出循环引用。如父对象有一个对子对象的引用,子对象反过来引用父对象。这样,他们的引用计数永远不可能为0。

2.1.3 是不是很无趣,来段代码压压惊

复制代码

public class abc_test {

    public static void main(String[] args) {
        // TODO Auto-generated method stub
        
        MyObject object1=new MyObject();
        MyObject object2=new MyObject();
        
        object1.object=object2;
        object2.object=object1;
        
        object1=null;
        object2=null;
        

    }

}

class MyObject{
    
     MyObject object;
     
}

复制代码

 
 

  这段代码是用来验证引用计数算法不能检测出循环引用。最后面两句将object1object2赋值为null,也就是说object1object2指向的对象已经不可能再被访问,但是由于它们互相引用对方,导致它们的引用计数器都不为0,那么垃圾收集器就永远不会回收它们。

2.2 可达性分析算法

  可达性分析算法是从离散数学中的图论引入的,程序把所有的引用关系看作一张图,从一个节点GC ROOT开始,寻找对应的引用节点,找到这个节点以后,继续寻找这个节点的引用节点,当所有的引用节点寻找完毕之后,剩余的节点则被认为是没有被引用到的节点,即无用的节点,无用的节点将会被判定为是可回收的对象。

 在Java语言中,可作为GC Roots的对象包括下面几种:(京东)

  a) 虚拟机栈中引用的对象(栈帧中的本地变量表);

  b) 方法区中类静态属性引用的对象;

  c) 方法区中常量引用的对象;

  d) 本地方法栈中JNI(Native方法)引用的对象。

 

这个算法的基本思路就是通过一系列的称为“GC Roots”的对象作为起始点,从这些节点开始向下搜索,搜索所走过的路径称为引用链(Reference Chain),当一个对象到GC Roots没有任何引用链相连(用图论的话来说,就是从GC Roots到这个对象不可达)时,则证明此对象是不可用的。如图所示,对象object 5、object 6、object 7虽然互相有关联,但是它们到GC Roots是不可达的,所以它们将会被判定为是可回收的对象。 

现在问题来了,可达性分析算法会不会出现对象间循环引用问题呢?答案是肯定的,那就是不会出现对象间循环引用问题。GC Root在对象图之外,是特别定义的“起点”,不可能被对象图内的对象所引用。

对象生存还是死亡(To Die Or Not To Die)

即使在可达性分析算法中不可达的对象,也并非是“非死不可”的,这时候它们暂时处于“缓刑”阶段,要真正宣告一个对象死亡,至少要经历两次标记过程:如果对象在进行可达性分析后发现没有与GC Roots相连接的引用链,那它将会被第一次标记并且进行一次筛选,筛选的条件是此对象是否有必要执行finapze()方法。当对象没有覆盖finapze()方法,或者finapze()方法已经被虚拟机调用过,虚拟机将这两种情况都视为“没有必要执行”。程序中可以通过覆盖finapze()来一场"惊心动魄"的自我拯救过程,但是,这只有一次机会呦。

复制代码

/**
 * 此代码演示了两点:
 * 1.对象可以在被GC时自我拯救。
 * 2.这种自救的机会只有一次,因为一个对象的finapze()方法最多只会被系统自动调用一次 
 * @author zzm
 */
pubpc class FinapzeEscapeGC {
  
 pubpc static FinapzeEscapeGC SAVE_HOOK = null;
  
 pubpc void isApve() {
  System.out.println("yes, i am still apve :)");
 }
  
 @Override
 protected void finapze() throws Throwable {
  super.finapze();
  System.out.println("finapze mehtod executed!");
  FinapzeEscapeGC.SAVE_HOOK = this;
 }
  
 pubpc static void main(String[] args) throws Throwable {
  SAVE_HOOK = new FinapzeEscapeGC();
  
  //对象第一次成功拯救自己
  SAVE_HOOK = null;
  System.gc();
  //因为finapze方法优先级很低,所以暂停0.5秒以等待它
  Thread.sleep(500);
  if (SAVE_HOOK != null) {
SAVE_HOOK.isApve();
  } else {
System.out.println("no, i am dead :(");
  }
  
  //下面这段代码与上面的完全相同,但是这次自救却失败了
  SAVE_HOOK = null;
  System.gc();
  //因为finapze方法优先级很低,所以暂停0.5秒以等待它
  Thread.sleep(500);
  if (SAVE_HOOK != null) {
SAVE_HOOK.isApve();
  } else {
System.out.println("no, i am dead :(");
  }
 }
}

复制代码

 运行结果为:

finapze mehtod executed! 
yes, i am still apve :)
no, i am dead :(

  

2.3 Java中的引用你了解多少

  无论是通过引用计数算法判断对象的引用数量,还是通过可达性分析算法判断对象的引用链是否可达,判定对象是否存活都与“引用”有关。在Java语言中,将引用又分为强引用、软引用、弱引用、虚引用4种,这四种引用强度依次逐渐减弱。无论是通过引用计数算法判断对象的引用数量,还是通过可达性分析算法判断对象的引用链是否可达,判定对象是否存活都与“引用”有关。在JDK 1.2以前,Java中的引用的定义很传统:如果reference类型的数据中存储的数值代表的是另外一块内存的起始地址,就称这块内存代表着一个引用。在JDK 1.2之后,Java对引用的概念进行了扩充,将引用分为强引用(Strong Reference)、软引用(Soft Reference)、弱引用(Weak Reference)、虚引用(Phantom Reference)4种,这4种引用强度依次逐渐减弱。

  • 强引用

  在程序代码中普遍存在的,类似 Object obj = new Object() 这类引用,只要强引用还存在,垃圾收集器永远不会回收掉被引用的对象。 

  • 软引用

  用来描述一些还有用但并非必须的对象。对于软引用关联着的对象,在系统将要发生内存溢出异常之前,将会把这些对象列进回收范围之中进行第二次回收。如果这次回收后还没有足够的内存,才会抛出内存溢出异常。

  • 弱引用

  也是用来描述非必需对象的,但是它的强度比软引用更弱一些,被弱引用关联的对象只能生存到下一次垃圾收集发生之前。当垃圾收集器工作时,无论当前内存是否足够,都会回收掉只被弱引用关联的对象。在JDK 1.2之后,提供了WeakReference类来实现弱引用。比如 threadlocal

  • 虚引用

  也叫幽灵引用或幻影引用(名字真会取,很魔幻的样子),是最弱的一种引用 关系。一个对象是否有虚引用的存在,完全不会对其生存时间构成影响,也无法通过虚引用来取得一个对象实例。它的作用是能在这个对象被收集器回收时收到一个系统通知。。在JDK 1.2之后,提供了PhantomReference类来实现虚引用。

  不要被概念吓到,也别担心,还没跑题,再深入,可就不好说了。小编罗列这四个概念的目的是为了说明,无论引用计数算法还是可达性分析算法都是基于强引用而言的。 

软引用使用示例:

复制代码

package jvm;
 
import java.lang.ref.SoftReference;
 
class Node {
pubpc String msg = "";
} 
pubpc class Hello {
pubpc static void main(String[] args) {
Node node1 = new Node(); // 强引用
node1.msg = "node1";
SoftReference<Node> node2 = new SoftReference<Node>(node1); // 软引用
node2.get().msg = "node2";
 
System.out.println(node1.msg);
System.out.println(node2.get().msg);
}
} 

复制代码

出结果为:

node2
node2 

 

2.4 对象死亡(被回收)前的最后一次挣扎

  即使在可达性分析算法中不可达的对象,也并非是“非死不可”,这时候它们暂时处于“缓刑”阶段,要真正宣告一个对象死亡,至少要经历两次标记过程。

  第一次标记:如果对象在进行可达性分析后发现没有与GC Roots相连接的引用链,那它将会被第一次标记;

  第二次标记:第一次标记后接着会进行一次筛选,筛选的条件是此对象是否有必要执行finalize()方法。在finalize()方法中没有重新与引用链建立关联关系的,将被进行第二次标记。

  第二次标记成功的对象将真的会被回收,如果对象在finalize()方法中重新与引用链建立了关联关系,那么将会逃离本次回收,继续存活。猿们还跟的上吧,嘿嘿。

2.5 方法区如何判断是否需要回收

  猿们,方法区存储内容是否需要回收的判断可就不一样咯。方法区主要回收的内容有:废弃常量和无用的类。对于废弃常量也可通过引用的可达性来判断,但是对于无用的类则需要同时满足下面3个条件:

  • 该类所有的实例都已经被回收,也就是Java堆中不存在该类的任何实例;
  • 加载该类的ClassLoader已经被回收;
  • 该类对应的java.lang.Class对象没有在任何地方被引用,无法在任何地方通过反射访问该类的方法。

关于类加载的原理,也是阿里面试的主角,面试官也问过我比如:能否自己定义String,答案是不行,因为jvm在加载类的时候会执行双亲委派,

原理请参考:Java 类加载机制(阿里面试题)


讲了半天,主角终于要粉墨登场了。

 

垃圾对象如何确定

Java堆中存放着几乎所有的对象实例,垃圾收集器在对堆进行回收前,首先需要确定哪些对象还"活着",哪些已经"死亡",也就是不会被任何途径使用的对象。 

三、常用的垃圾收集算法

3.0 引用计数法

引用计数法实现简单,效率较高,在大部分情况下是一个不错的算法。其原理是:给对象添加一个引用计数器,每当有一个地方引用该对象时,计数器加1,当引用失效时,计数器减1,当计数器值为0时表示该对象不再被使用。需要注意的是:引用计数法很难解决对象之间相互循环引用的问题,主流Java虚拟机没有选用引用计数法来管理内存。

复制代码

public class abc_test {

    public static void main(String[] args) {
        // TODO Auto-generated method stub
        
        MyObject object1=new MyObject();
        MyObject object2=new MyObject();
        
        object1.object=object2;
        object2.object=object1;
        
        object1=null;
        object2=null;

    }

}

class MyObject{
    
     MyObject object;
     
}

复制代码

 

3.1 标记-清除算法(Mark-Sweep) 

这是最基础的垃圾回收算法,之所以说它是最基础的是因为它最容易实现,思想也是最简单的。标记-清除算法分为两个阶段:标记阶段和清除阶段。标记阶段的任务是标记出所有需要被回收的对象,清除阶段就是回收被标记的对象所占用的空间。具体过程如下图所示:

从图中可以很容易看出标记-清除算法实现起来比较容易,但是有一个比较严重的问题就是容易产生内存碎片,碎片太多可能会导致后续过程中需要为大对象分配空间时无法找到足够的空间而提前触发新的一次垃圾收集动作。  

标记-清除算法采用从根集合(GC Roots)进行扫描,对存活的对象进行标记,标记完毕后,再扫描整个空间中未被标记的对象,进行回收,如下图所示。标记-清除算法不需要进行对象的移动,只需对不存活的对象进行处理,在存活对象比较多的情况下极为高效,但由于标记-清除算法直接回收不存活的对象,因此会造成内存碎片。

3.2 复制算法(Copying)

为了解决Mark-Sweep算法的缺陷,Copying算法就被提了出来。它将可用内存按容量划分为大小相等的两块,每次只使用其中的一块。当这一块的内存用完了,就将还存活着的对象复制到另外一块上面,然后再把已使用的内存空间一次清理掉,这样一来就不容易出现内存碎片的问题。具体过程如下图所示:

这种算法虽然实现简单,运行高效且不容易产生内存碎片,但是却对内存空间的使用做出了高昂的代价,因为能够使用的内存缩减到原来的一半。

很显然,Copying算法的效率跟存活对象的数目多少有很大的关系,如果存活对象很多,那么Copying算法的效率将会大大降低。  

复制算法的提出是为了克服句柄的开销和解决内存碎片的问题。它开始时把堆分成 一个对象 面和多个空闲面, 程序从对象面为对象分配空间,当对象满了,基于copying算法的垃圾 收集就从根集合(GC Roots)中扫描活动对象,并将每个 活动对象复制到空闲面(使得活动对象所占的内存之间没有空闲洞),这样空闲面变成了对象面,原来的对象面变成了空闲面,程序会在新的对象面中分配内存。

3.3 标记-整理算法(Mark-compact)

为了解决Copying算法的缺陷,充分利用内存空间,提出了Mark-Compact算法。该算法标记阶段和Mark-Sweep一样,但是在完成标记之后,它不是直接清理可回收对象,而是将存活对象都向一端移动(美团面试题目,记住是完成标记之后,先不清理,先移动再清理回收对象),然后清理掉端边界以外的内存(美团问过)   

标记-整理算法采用标记-清除算法一样的方式进行对象的标记,但在清除时不同,在回收不存活的对象占用的空间后,会将所有的存活对象往左端空闲空间移动,并更新对应的指针。标记-整理算法是在标记-清除算法的基础上,又进行了对象的移动,因此成本更高,但是却解决了内存碎片的问题。具体流程见下图:

3.4 分代收集算法 Generational Collection(分代收集)算法   

分代收集算法是目前大部分JVM的垃圾收集器采用的算法。它的核心思想是根据对象存活的生命周期将内存划分为若干个不同的区域。一般情况下将堆区划分为老年代(Tenured Generation)和新生代(Young Generation),在堆区之外还有一个代就是永久代(Permanet Generation)。老年代的特点是每次垃圾收集时只有少量对象需要被回收,而新生代的特点是每次垃圾回收时都有大量的对象需要被回收,那么就可以根据不同代的特点采取最适合的收集算法。

目前大部分垃圾收集器对于新生代都采取Copying算法,因为新生代中每次垃圾回收都要回收大部分对象,也就是说需要复制的操作次数较少,但是实际中并不是按照1:1的比例来划分新生代的空间的,一般来说是将新生代划分为一块较大的Eden空间和两块较小的Survivor空间(一般为8:1:1),每次使用Eden空间和其中的一块Survivor空间,当进行回收时,将Eden和Survivor中还存活的对象复制到另一块Survivor空间中,然后清理掉Eden和刚才使用过的Survivor空间

而由于老年代的特点是每次回收都只回收少量对象,一般使用的是Mark-Compact算法。

3.4.1 年轻代(Young Generation)的回收算法 (回收主要以Copying为主)

a) 所有新生成的对象首先都是放在年轻代的。年轻代的目标就是尽可能快速的收集掉那些生命周期短的对象。

b) 新生代内存按照8:1:1的比例分为一个eden区和两个survivor(survivor0,survivor1)区。一个Eden区,两个 Survivor区(一般而言)。大部分对象在Eden区中生成。回收时先将eden区存活对象复制到一个survivor0区,然后清空eden区,当这个survivor0区也存放满了时,则将eden区和survivor0区存活对象复制到另一个survivor1区,然后清空eden和这个survivor0区,此时survivor0区是空的,然后将survivor0区和survivor1区交换,即保持survivor1区为空(美团面试,问的太细,为啥保持survivor1为空,答案:为了让eden和survivor0 交换存活对象), 如此往复。当Eden没有足够空间的时候就会 触发jvm发起一次Minor GC

c) 当survivor1区不足以存放 eden和survivor0的存活对象时,就将存活对象直接存放到老年代。若是老年代也满了就会触发一次Full GC(Major GC),也就是新生代、老年代都进行回收。

d) 新生代发生的GC也叫做Minor GC,MinorGC发生频率比较高(不一定等Eden区满了才触发)。

3.4.2 年老代(Old Generation)的回收算法(回收主要以Mark-Compact为主)

a) 在年轻代中经历了N次垃圾回收后仍然存活的对象,就会被放到年老代中。因此,可以认为年老代中存放的都是一些生命周期较长的对象。

b) 内存比新生代也大很多(大概比例是1:2),当老年代内存满时触发Major GC即Full GC,Full GC发生频率比较低,老年代对象存活时间比较长,存活率标记高。

3.4.3 持久代(Permanent Generation)(也就是方法区)的回收算法

  用于存放静态文件,如Java类、方法等。持久代对垃圾回收没有显著影响,但是有些应用可能动态生成或者调用一些class,例如Hibernate 等,在这种时候需要设置一个比较大的持久代空间来存放这些运行过程中新增的类。持久代也称方法区,具体的回收可参见上文2.5节。

  再写一遍:

        方法区存储内容是否需要回收的判断可就不一样咯。方法区主要回收的内容有:废弃常量和无用的类。对于废弃常量也可通过引用的可达性来判断,但是对于无用的类则需要同时满足下面3个条件:

  • 该类所有的实例都已经被回收,也就是Java堆中不存在该类的任何实例;
  • 加载该类的ClassLoader已经被回收;
  • 该类对应的java.lang.Class对象没有在任何地方被引用,无法在任何地方通过反射访问该类的方法。

 

 5 新生代和老年代的区别(阿里面试官的题目): 

**所谓的新生代和老年代是针对于分代收集算法来定义的,新生代又分为Eden和Survivor两个区。加上老年代就这三个区。数据会首先分配到Eden区 当中(当然也有特殊情况,如果是大对象那么会直接放入到老年代(大对象是指需要大量连续内存空间的java对象)。),当Eden没有足够空间的时候就会 触发jvm发起一次Minor GC。如果对象经过一次Minor GC还存活,并且又能被Survivor空间接受,那么将被移动到Survivor空 间当中。并将其年龄设为1,对象在Survivor每熬过一次Minor GC,年龄就加1,当年龄达到一定的程度(默认为15)时,就会被晋升到老年代 中了,当然晋升老年代的年龄是可以设置的。如果老年代满了就执行:Full GC 因为不经常执行,因此采用了 Mark-Compact算法清理

其实新生代和老年代就是针对于对象做分区存储,更便于回收等等**


猿们加油跟上,离offer不远啦!!!

 

四、常见的垃圾收集器

下面一张图是HotSpot虚拟机包含的所有收集器,图是借用过来滴:

  • Serial收集器(复制算法)
    新生代单线程收集器,标记和清理都是单线程,优点是简单高效。是client级别默认的GC方式,可以通过-XX:+UseSerialGC来强制指定。
  • Serial Old收集器(标记-整理算法)
    老年代单线程收集器,Serial收集器的老年代版本。
  • ParNew收集器(停止-复制算法) 
    新生代收集器,可以认为是Serial收集器的多线程版本,在多核CPU环境下有着比Serial更好的表现。
  • Parallel Scavenge收集器(停止-复制算法)
    并行收集器,追求高吞吐量,高效利用CPU。吞吐量一般为99%, 吞吐量= 用户线程时间/(用户线程时间+GC线程时间)。适合后台应用等对交互相应要求不高的场景。是server级别默认采用的GC方式,可用-XX:+UseParallelGC来强制指定,用-XX:ParallelGCThreads=4来指定线程数。
  • Parallel Old收集器(停止-复制算法)
    Parallel Scavenge收集器的老年代版本,并行收集器,吞吐量优先。
  • CMS(Concurrent Mark Sweep)收集器(标记-清理算法)
    高并发、低停顿,追求最短GC回收停顿时间,cpu占用比较高,响应时间快,停顿时间短,多核cpu 追求高响应时间的选择。
  • CMS 和G1的垃圾回收器的原理,阿里的面试官也问过,我专门做了专题:
  • 参考:图解 CMS 垃圾回收机制原理,-阿里面试题
  • 参考:CMS收集器和G1收集器优缺点-阿里面试题
  • 参考:G1 垃圾收集器入门

五、GC是什么时候触发的(面试最常见的问题之一)

  由于对象进行了分代处理,因此垃圾回收区域、时间也不一样。GC有两种类型:Scavenge GC和Full GC。

5.1 Scavenge GC

  一般情况下,当新对象生成,并且在Eden申请空间失败时,就会触发Scavenge GC,对Eden区域进行GC,清除非存活对象,并且把尚且存活的对象移动到Survivor区。然后整理Survivor的两个区。这种方式的GC是对年轻代的Eden区进行,不会影响到年老代。因为大部分对象都是从Eden区开始的,同时Eden区不会分配的很大,所以Eden区的GC会频繁进行。因而,一般在这里需要使用速度快、效率高的算法,使Eden去能尽快空闲出来。

5.2 Full GC

  对整个堆进行整理,包括Young、Tenured和Perm。Full GC因为需要对整个堆进行回收,所以比Scavenge GC要慢,因此应该尽可能减少Full GC的次数。在对JVM调优的过程中,很大一部分工作就是对于Full GC的调节。有如下原因可能导致Full GC:

a) 年老代(Tenured)被写满;

b) 持久代(Perm)被写满;

c) System.gc()被显示调用;

d) 上一次GC之后Heap的各域分配策略动态变化;

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

JVM的垃圾回收机制 总结(垃圾收集、回收算法、垃圾回收器) 的相关文章

  • 在 Java 中重置 Graphics2D 对象

    我正在用 Java 尝试 Graphics2D 但像往常一样 我被困住了 P 问题是 假设我有这个代码 Graphics2D g Graphics2D this getGraphics Inside a JFrame g rotate Ma
  • 面试问题 - 在排序数组 X 中搜索索引 i,使得 X[i] = i

    昨天面试时 我被问到了以下问题 考虑一个 Java 或 C 数组X它已排序并且其中没有两个元素是相同的 如何最好地找到索引i这样该索引处的元素也是i 那是X i i 作为澄清 她还给了我一个例子 Array X 3 1 0 3 5 7 in
  • 模拟框架对我有什么作用?

    我听说有些我无法交谈的人是 jmock 的忠实粉丝 我已经做了以测试为中心的开发多年 所以我浏览了网站并查看了一些文档 但仍然不知道它有什么好处 我对春天也有同样的问题 如果您已经了解它是什么 他们的文档会很好地解释它 所以我并不认为 jm
  • 使用 ScheduledExecutorService 安排每月任务

    我想在该月的某一天的特定时间安排一项任务 每次运行之间的间隔可以设置在 1 到 12 个月之间 在java中 可以使用ScheduledExecutorService以固定的时间间隔调度任务 既然一个月的天数不固定 那么如何实现呢 提前致谢
  • C# 中的 Culture 相当于 Java 中的 Locale 吗?

    C 使用文化的概念 这在操作上与 Java 中的 Locale 类似吗 或者底层概念是否存在显着差异 从文化而不是语言环境的角度进行工作是一种寻找正确抽象层次的尝试 从以类似方式做事的人群的角度来考虑事物 而不是谈论地理区域和语言 并有点疯
  • Android - Java - 发送 facebook 聊天消息的意图(facebook 禁用 xmpp)

    Facebook 已弃用 xmpp API 有没有办法打开意图 或将数据传递到fb 以在Android设备上发送聊天消息 设备上安装的 Facebook 和 Messenger 应用 谢谢 您需要将 uri 传递给意图 这里10000572
  • Java 创建 Thread 实例时会发生什么

    我有一个关于 Java 线程和操作系统线程的问题 我读了Java 线程与 Pthreads https stackoverflow com questions 5269535 java threads vs pthreads and Jav
  • 让 Java 与 Windows 10 Ubuntu 一起使用

    我安装了 Windows 10 周年更新 以便可以在 Windows 上的 Ubuntu 上尝试 Bash 看如何安装 http www howtogeek com 249966 how to install and use the lin
  • 使用 javax.mail 和 CentOS 的邮件服务器

    我有一个 Java 程序 安装在一台旧的 Ubuntu 机器上 并使用 javax mail 发送邮件 然而 那台机器宕机了 我现在在新的 CentOS 机器上运行相同的 Java 应用程序 但是 当我尝试使用 mail smtp host
  • Java 中 LINQ 的等价物是什么? [关闭]

    Closed 此问题正在寻求书籍 工具 软件库等的推荐 不满足堆栈溢出指南 help closed questions 目前不接受答案 Java 中 LINQ 的等价物是什么 没有什么比 LINQ for Java 更好的了 Edit 现在
  • JFreeChart MeterPlot

    我目前正在用java做Agent项目 在某些时候 我需要显示一个仪表 例如 电池电量 我的程序中有 5 个代理 每个代理都会创建自己的带有名称的仪表图 但不知何故他们没有更新数据集 或者他们正在更新数据集 只是它没有显示在仪表图上 任何想法
  • 如何迭代SparseArray?

    有没有办法迭代 Java SparseArray 适用于 Android 我用了sparsearray通过索引轻松获取值 我找不到 看来我找到了解决方案 我没有正确注意到keyAt index 功能 所以我会这样做 for int i 0
  • GAE - Eclipse 中的开发服务器未更新?

    我在 Eclipse 上使用 Google AppEngine 开发服务器 我的本地网页似乎没有更新 直到我在开发服务器上进行了多次重新启动 使用 Eclipse 中的 运行 或 调试 按钮 我究竟做错了什么 基本流程是 更改 java 文
  • 如何将我的自定义相机应用程序设置为默认应用程序?

    如果我使用以下代码 Intent takePictureIntent new Intent MediaStore ACTION IMAGE CAPTURE startActivityForResult takePictureIntent 1
  • 无法运行简单的 doclet 程序:包 com.sun.javadoc 不存在

    我正在尝试运行一个简单的 doclet 程序 但无法编译它 javac cp cygdrive c Progra 2 Java jdk1 8 0 65 lib tools jar A java 但它抛出 A java 1 错误 包 com
  • 当相应的 JTextfield 为空时,如何填充 JTable 中的所有项目

    我正在 Java 项目中设计一个高级搜索选项sqlite在 NetBeans 中 有5种不同JTextfields和 5 列 我想填充JTable具有相应的匹配标准 如果一个JTextfield为空 那么它应该选择该列的所有项目 我使用的查
  • 何时以及为何使用缓冲输入和输出流? [关闭]

    Closed 这个问题需要细节或清晰度 help closed questions 目前不接受答案 我读到这些是为了减少磁盘 网络调用开销而使用的 这在写操作的情况下似乎很好 但是进行缓冲读取有什么好处呢 如果您按字节读取文件 则每次都会进
  • Spring Boot 健康执行器 - 什么时候上线?

    我找不到任何有关 Springs Health Actuator 何时返回 UP 状态的文档 你能依靠一切吗 Components正在初始化 会不会 Controller准备好满足请求了吗 为了测试应用程序上下文是否已加载 您可以执行此自定
  • SAXParseException:找不到元素“定义”的声明

    我对 camunda 和 DMN 完全陌生 我试图在 spring boot 中运行 DMN 示例 链接在这里 https github com camunda camunda bpm examples tree master dmn en
  • 跳过一行GridBagLayout

    我在 JFrame 上使用 GridBagLayout 我希望能够跳过一两行 但将这些行显示为空白 然后在这些行后面有一个按钮 我在文档中找不到任何方法来执行我所描述的操作 有谁知道我可以执行此操作的任何方法吗 发现它比添加空组件干净得多

随机推荐

  • 在centos安装redis,完成数据迁移,安装python3.6部署项目到服务器上

    1 安装redis 第一步 进入想要安装的目录下载压缩包 cd wget http download redis io releases redis 3 0 0 tar gz 第二步 解压压缩包安装redis tar zxvf redis
  • 李沐基于Pytorch的深度学习笔记(10)-Softmax回归-几种常用损失函数介绍:均方损失、绝对值损失、Huber‘s robust损失(代码在后面章节)

    1 均方损失 第一种是均方损失 1 2和平方是为了方便求导 其中 蓝色曲线是当Y 0时 变换预测值Y 的函数 绿色是似然函数 橙色表示梯度 梯度下降时 对负梯度方向会更新梯度 所以它的导数就是可以看出参数的一个更新 2 绝对值损失 这种定义
  • VC++6.0 IDE的工程用Code::Blocks来打开、编译、调试终极配置方案

    引子 竟然可以用Code Blocks来打开 编译 调试VC 6 0的项目 感觉很神奇 通过配置也让我们更进一步了解VC 6 0的编译器 连接器 调试器 好多兄弟问到要是能支持最新的VS2008和VS2010就好了 其实Code Block
  • SQL数据表层面操作(DDL)

    DDL Data Definition Language 数据定义语言 用于对数据库和数据表的操作 因为操作对象有两个 数据库和数据表 所以我们要在每个命令之后 create drop alter show后面加上database或者tab
  • jstat使用详解(jvm问题排查)

    jstat命令使用 jstat命令可以查看堆内存各部分的使用量 以及加载类的数量 命令的格式如下 jstat 命令选项 vmid 间隔时间 毫秒 查询次数 注意 使用的jdk版本是jdk8 类加载统计 C Users Administrat
  • 联盟链选型之FISCO BCOS

    算起来从去年12 31开始 到现在 已经快满三个月了 这三个月 阅读了各种区块链白皮书 腾讯的 华为的 京东的 可信区块链组织的 组织了一份 dfgx区块链解决方案 参加了华为组织的区块链生态 其实主要是推他自己的目录链 目前区块链这个概念
  • 快递E栈项目实战第二阶段

    快递E栈项目实战第二阶段 文章目录 快递E栈项目实战第二阶段 1 阶段二需求 2 模块分析 3 代码结构和运行截图 4 源码 1 阶段二需求 2 模块分析 1 V视图展示 欢迎 菜单 子菜单 2 D数据存储 快递数据 gt 存取媒介更改为数
  • urllib的使用

    See PyCharm help at https www jetbrains com help pycharm import urllib request 设置关闭本地验证 import ssl import urllib parse s
  • 文件流之文件输出流FileOutputStream

    一 介绍 FileOutputStream实现了向文件中写入byte数据的方法 二 打印数据到文件 package com imooc io import java io FileOutputStream import java io IO
  • 机器学习sklearn-支持向量机1

    目录 相关概念 线性SVM决策过程的可视化 相关概念 支持向量机的分类方法 是在这组分布中找出一个超平面作为决策边界 使模型在数据上的 分类误差尽量接近于小 尤其是在未知数据集上的分类误差 泛化误差 尽量小 边际很小的情况 是一种模型在训练
  • Out of memory

    环境 Ubuntu Server 12 04 i686 问题描述 24G内存 空闲的有20G左右 但是内核老是报这个 动不动就杀程序 Jul 6 13 12 44 00098 kernel 3112325 883069 Out of mem
  • 利用mongodb实现分布式WEB图片存储

    利用mongodb实现分布式WEB图片存储 2012 12 22 14 00 33 标签 mongodb 分布式图片存储 nginx 分布式网站 的确在站比较小得时候 附件不多的时候 当然这样处理很好 但是当 附件数量海里去了 那这样存就蛋
  • Sass中@each、@for、@if的搭配使用

    CSS 预处理器赋予了 CSS 逻辑编程的能力 其中 Sass Less Stylus 最受欢迎 语法都是大同小异 上手也很快 在项目中使用最多的可能要数 Sass 了 本文就讲讲 Sass 中循环遍历 each for 和 if 判断的搭
  • SpringBoot 返回json数据 的几种方式

    一 RestController RequestMapping RestController public class TestController RequestMapping public User test User user new
  • LeetCode/LintCode 题解丨一周爆刷字符串:URL 编码

    描述 给出一个代表网址 host 的字符串 base url 和代表查询参数的列表 query params list 你需要返回带查询参数的完整 URL 查询参数列表由一些包含两个元素的数组组成 数组第一个元素代表参数 数组第二个元素代表
  • 8-js高级-4

    JavaScript 进阶 4 深浅拷贝 浅拷贝 浅拷贝 把对象拷贝给一个新的对象 开发中我们经常需要复制一个对象 如果直接赋值 则复制的是地址 修改任何一个对象 另一个对象都会变化 常见方法 拷贝对象 Object assgin 展开运算
  • postgresql安装报错

    postgresql安装报错 版本问题 版本问题 第一次下载安装postgresql 进到官网 随便点了一个12得版本进行下载 postgresql 12 12 1 windows x64 下载后双击运行 直接提示 百度了一圈 有说 用管理
  • Python实战RBF神经网络

    程序员A 哥们儿 最近手头紧 借点钱 程序员B 成啊 要多少 A 1000行不 B 咱俩谁跟谁 给你凑个整 这1024 拿去吧 之前我们讲了神经网络 人工神经网络是受到人类大脑结构的启发而创造出来的 这也是它能拥有真智能的根本原因 在我们的
  • pycharm创建py脚本自动增加注释和描述

    pycharm创建py脚本自动增加注释和描述 创建脚本时可自动带入简单注释 设备 MAC 注释内容如下 Time DATE TIME Author fanzw File NAME py Description 可自由扩展 效果如下
  • JVM的垃圾回收机制 总结(垃圾收集、回收算法、垃圾回收器)

    如果想了解Java内存模型参考 jvm内存模型 和内存分配以及jdk jre jvm是什么关系 阿里 美团 京东 相信和小编一样的程序猿们在日常工作或面试当中经常会遇到JVM的垃圾回收问题 有没有在夜深人静的时候详细捋一捋JVM垃圾回收机制