几张图可以理解GC JVM调优的内容


public class ApiPurchaseOrderServiceApp {public static void main(String[] args) throws Exception {ApiPurchaseOrderServiceApp m=new ApiPurchaseOrderServiceApp();m.compute();//栈System.out.println("ok");//方法出口}public  int compute(){int a=1;//局部变量表int b=2;int c=(a+b)*10;//操作数栈return c;}
}

Javap -c ApiPurchaseOrderServiceApp.class > aa.txt或Javap -v ApiPurchaseOrderServiceApp.class > aa.txt 可以查看.class文件的源码文件到指令码,

概念

程序计数器:code部分是 程序计数器的部分 代表当前执行的行

操作数栈:是从局部变量表里拿出变量计算使用的临时栈

动态链接:栈内执行方法与方法区里加在类的方法 映射使用的指针

方法出口:就是栈帧结束后,返回到上一方法的code地址

堆:放new 的方法

本地方法栈:比如thread下native的start0  是调用windows下c++产生的start0方法,时候,临时使用的栈

方法区:元空间 存放 常量 静态变量 类元信息等 就是Java的要被执行的方法和类被定义的地方 使用物理直接内存,比如4G内存物理,3G xmx内存,剩下1G物理内存,方法区使用的内存就是1G里

eden survivor0 survivor1 :新生代 依次慢了被GC回收

old:老年代 一直存在的,如线程池 数据库连接池

GC ROOT:类装载器 jvm虚拟映射指针

  • 通过System Class Loader或者Boot Class Loader加载的class对象,通过自定义类加载器加载的class不一定是GC Root
  • 处于激活状态的线程
  • 栈中的对象
  • JNI栈中的对象
  • JNI中的全局对象
  • 正在被用于同步的各种锁对象
  • JVM自身持有的对象,比如系统类加载器等。
  • 常用的GC算法

  • 标记回收算法
    从GC root进行遍历,把可达对象都标记,剩下那些不可达的进行回收,这种方式需要中断其他线程,并且可能产生内存碎片

  • 复制算法
    把内存区域分为两块,每次使用一块,GC的时候把一块中的内容移动到另一块中,原始内存中的对象就可以被回收了。

  • 标记压缩算法
    和标记回收差不多,但是在回收的时候会对可达对象进行整理,将其压缩到内存的一段,避免内存碎片

  • 分代算法
    将内存区域分代,对不同的代使用不同的回收算法,通常分为新生代,老年代,和永久带。
    新生代一般包含三个区域,Eden区和两个Survivor区,新生代一般采用复制算法

 

 

    JVM调优主要就是调整下面两个指标
    停顿时间:垃圾收集器做垃圾回收中断应用执行的时间。
    -XX:Max GC Pause Millis
    吞吐量:垃圾收集的时间和总时间的占比:1/(1+n),吞吐量为1-1/(1+n)。
    -XX:GCTimeRatio=n
    GC调优步骤
    打印GC日志
    -XX:+PrintGCDetails-XX:+PrintGCTimeStamps -XX:+PrntGCDateStamps -Xloggc:./go.log
    Tomcat则直接加在JAVA_OPTS变量里
              分析日志得到关键性指标
              分析GC原因, 调优JVM参数
    1、Parallel Scavenge收集器(默认)
    分析parallel-gc.log
    调优:
    第一次调优, 设置Meta space大小:增大元空间大小-XX:MetaspaceSize=64M-XX:MaxMetaspaceSize=64M
    第二次调优, 增大年轻代动态扩容增量, 默认是20(%) , 可以减少young gc:-XX:YoungGenerationSizeIncrement=30
    比较下几次调优效果:
    吞吐量   最大停顿  页  平均停  Young gc  Full gc
    98.356%  120ms     1    19ms   19        2
    99.252%  20ms           10ms   16        0

 2、配置CMS收集器
    -XX:+Use Conc Mark Sweep GC
    分析cms-gc.log
3、配置G1收集器
    -XX:+UseG1GC
    分析g 1-gc.log
    young GC:[GC pause(G 1 Evacuation Pause) (young)
    initial-mark:[GC pause(Metadata GC Threshold) (young) (initial-mark)) (参数:Initiating Heap Occupancy Percent)
    mixed GC:[GC pause(G 1 Evacuation Pause) (mixed) (参数:G1Heap Waste Percent)
    full GC:[Full GC(Allocation Failure) (无可用region)
    (G 1内部, 前面提到的混合GC是非常重要的释放内存机制, 它避免了G 1出现Region没有可用的情况, 否则就会触发Full GC事件。
    CMS, Parallel.Serial GC都需要通过Full GC去压缩老年代并在这个过程中扫描整个老年代。G 1的Full GC算法和Serial GC收集器完全一致, 当一个
    Full GC发生时, 整个Java堆执行一个完整的压缩, 这样确保了最大的空余内存可用。G 1的Full GC是一个单线程, 它可能引起一个长时间的停顿时
    间, G 1的设计目标是减少Full GC, 满足应用性能目标。)
    查看发生Mixed GC的阈值:j info-flag Initiating Heap Occupancy Percent进程id
    调优:
    第一次调优, 设置Meta space大小:增大元空间大小-XX:MetaspaceSize=64M-XX:MaxMetaspaceSize=64M
    第二次调优, 添加严叶量和停顿肚间参数-yy-GC timeR atic-80-XX Mar GC Pause Mi= 100

    井行收集器设置
    -XX:ParallelGCThreads:设置并行收集器收集时使用的CPU数。并行收集线程数。
    -XX:MaxGCPauseMilis:设置并行收集最大暂停时间
    -XX:GCTimeRatio:设置垃圾回收时间占程序运行时间的百分比。公式为1/(1+n)
    -XX:YoungGenerationSizeIncrement:年轻代gc后扩容比例,默认是20(%)
    CMS收集器设置
    -XX:+Use Conc Mark Sweep GC:设置CMS井发收集器
    -XX:+CMS Incremental Mode:设置为增量模式, 适用于单CPU情况。
    -XX:ParallelGCThreads:设置并发收集器新生代收集方式为并行收集时, 使用的CPU数。并行收集线程数。
    -XX:CMSFullGCsBeloreCompacion:设定进行多少次CMS垃圾回收后,进行一次内存压缩
    -XX:+CMS Class Ur loading Enabled:允许对元数据进行回收
    -XX:UseCMSIniiatingQccupancyOnly:表示只在到达阀值的时候,才进行CMS回收
    -XX:+CMS In creme nl al Mode:设置为增量模式。适用于单CPU情况
    -XX:ParallelCMSThreads:设定CMS的线程数量
    -XX:CMSInitiaingOccupancyFraction:设置CMS收集器在老年代空间被使用多少后触发
    -XX:+Use CMS Compact At Full Colection:设置CMS收集器在完成垃圾收集后是否要进行一次内存碎片的整理

      G1收集器设置
    -XX:+UseG1GC:使用G 1收集器
    -XX:ParallelGCThreads:指定GC工作的线程数量
    -XX:G1HeapRegionSize:指定分区大小(1MB-32MB,且必须是2的霉),默认将整堆划分为2048个分区
    -XX:GCTimeRatio:吞吐量大小,0-100的整数(默认9),值为n则系统将花费不超过1/(1+n)的时间用于垃圾收集
    -XX:MaxGCPauseMillis:目标暂停时间(默认200ms)
    -XX:G1NewSizePercent:新生代内存初始空间(默认整堆5%)
    -XX:G1MaxNewSizePercent新生代内存最大空间
    -XX:TargetSurvvorRatio;Survivor填充容量(默认50%)
    -XX:MaxTenuringThreshold:最大任期值(默认15)
    -xX:InitiatingHeapOccupancyPercen:老年代占用空间超过整堆比IHOPI值(默认45%)超过则执行混合收集
    XX:G1HeapWastePercent:堆废物百分比(默认5%)

 

分代收集的概念是指在不同的代上使用不同的垃圾回收算法,一般来讲 在新生代上使用复制算法,在老年代上使用标记清理或者标记压缩算法。在永久代上使用标记压缩算法(JVM规范并没有要求要对永久代进行回收)。

垃圾收集器是GC的具体实现,不同的垃圾收集器针对的代也是不一样的,简单介绍一下。

Serial收集器:主要针对针对新生代,什么都不配置的话JVM默认的收集器,采用复制算法
ParNew收集器:主要 针对新生代, Serial的多线程版本。

Parallel Scanvenge: 主要针对新生代,主要用在服务器上,这种垃圾收集器也是采用复制算法,但是关注CPU吞吐量,强调CPU运行垃圾回收的时间和CPU执行用户代码的时间的比例。

Serial Old收集器:主要针对老年代,采用标记清理和标记压缩算法,单线程版本

Parallel Old收集器:主要针对老年代,多线程版本。

CMS(Concurrent Mark Sweep):大名鼎鼎的并行标记清理收集器,主要针对老年代,多线程,主要关注停顿时间,这个在嵌入式设备上非常有名,因为用户对于停顿时间很敏感。

CMS的原理是三次标记一次清除。
第一次标记先找到应用中所有的GC root,这次标记需要暂停用户线程。但是时间非常非常短。
第二次标记不需要暂停用户线程,根据第一次标记的结果去寻找不可达对象。
第三次标记也需要暂停用户线程,因为在第二次标记的过程中,GC root可能发生了变化,这个时候就要在把变化的重新标记一下。

三次标记完成之后就会执行清理过程。

由于在第二次并行标记的时候用户线程仍然在执行,所以需要预留足够的内存给用户线程使用,所以CMS并不会在老年代满了之后才执行Full GC, 一般是在老年代使用了一大半的时候就会执行一次Full GC.

同样的,CMS由于采用标记清理算法,也会导致内存碎片的产生。

并发清理是指:垃圾清理的过程中用户线程还可以继续工作,所以CMS是并发收集器。

并行清理是指:有多个垃圾回收线程在执行清理,所以Parallel收集器是并行收集器

-------------------------------常见调优:

 

1. 串行收集器

串行收集器是最古老,最稳定以及效率高的收集器
可能会产生较长的停顿,只使用一个线程去回收
-XX:+UseSerialGC

  • 新生代、老年代使用串行回收
  • 新生代复制算法
  • 老年代标记-压缩

串行收集器的日志输出:

 

 
  1. 0.844: [GC 0.844: [DefNew: 17472K->2176K(19648K), 0.0188339 secs] 17472K->2375K(63360K), 0.0189186 secs] [Times: user=0.01 sys=0.00, real=0.02 secs]8.259: [Full GC 8.259: [Tenured: 43711K->40302K(43712K), 0.2960477 secs] 63350K->40302K(63360K), [Perm : 17836K->17836K(32768K)], 0.2961554 secs] [Times: user=0.28 sys=0.02, real=0.30 secs]

     

  2.  

2. 并行收集器

2.1 ParNew

-XX:+UseParNewGC(new代表新生代,所以适用于新生代)

  • 新生代并行
  • 老年代串行

Serial收集器新生代的并行版本
在新生代回收时使用复制算法
多线程,需要多核支持
-XX:ParallelGCThreads 限制线程数量

并行收集器的日志输出:

0.834: [GC 0.834: [ParNew: 13184K->1600K(14784K), 0.0092203 secs] 13184K->1921K(63936K), 0.0093401 secs] [Times: user=0.00 sys=0.00, real=0.00 secs]

2.2 Parallel收集器

类似ParNew 
新生代复制算法 
老年代标记-压缩 
更加关注吞吐量 
-XX:+UseParallelGC  

  • 使用Parallel收集器+ 老年代串行

-XX:+UseParallelOldGC 

  • 使用Parallel收集器+ 老年代并行

Parallel收集器的日志输出:

1.500: [Full GC [PSYoungGen: 2682K->0K(19136K)] [ParOldGen: 28035K->30437K(43712K)] 30717K->30437K(62848K) [PSPermGen: 10943K->10928K(32768K)], 0.2902791 secs] [Times: user=1.44 sys=0.03, real=0.30 secs]

2.3 其他GC参数

-XX:MaxGCPauseMills

  • 最大停顿时间,单位毫秒
  • GC尽力保证回收时间不超过设定值

-XX:GCTimeRatio 

  • 0-100的取值范围
  • 垃圾收集时间占总时间的比
  • 默认99,即最大允许1%时间做GC

这两个参数是矛盾的。因为停顿时间和吞吐量不可能同时调优

3. CMS收集器

  • Concurrent Mark Sweep 并发标记清除(应用程序线程和GC线程交替执行)
  • 使用标记-清除算法
  • 并发阶段会降低吞吐量(停顿时间减少,吞吐量降低)
  • 老年代收集器(新生代使用ParNew)
  • -XX:+UseConcMarkSweepGC

CMS运行过程比较复杂,着重实现了标记的过程,可分为

1. 初始标记(会产生全局停顿)

  • 根可以直接关联到的对象
  • 速度快

2. 并发标记(和用户线程一起) 

  • 主要标记过程,标记全部对象

3. 重新标记 (会产生全局停顿) 

  • 由于并发标记时,用户线程依然运行,因此在正式清理前,再做修正

4. 并发清除(和用户线程一起) 

  • 基于标记结果,直接清理对象

这里就能很明显的看出,为什么CMS要使用标记清除而不是标记压缩,如果使用标记压缩,需要多对象的内存位置进行改变,这样程序就很难继续执行。但是标记清除会产生大量内存碎片,不利于内存分配。 

CMS收集器的日志输出:

 

 
  1. 1.662: [GC [1 CMS-initial-mark: 28122K(49152K)] 29959K(63936K), 0.0046877 secs] [Times: user=0.00 sys=0.00, real=0.00 secs]1.666: [CMS-concurrent-mark-start]1.699: [CMS-concurrent-mark: 0.033/0.033 secs] [Times: user=0.25 sys=0.00, real=0.03 secs]1.699: [CMS-concurrent-preclean-start]1.700: [CMS-concurrent-preclean: 0.000/0.000 secs] [Times: user=0.00 sys=0.00, real=0.00 secs]1.700: [GC[YG occupancy: 1837 K (14784 K)]1.700: [Rescan (parallel) , 0.0009330 secs]1.701: [weak refs processing, 0.0000180 secs] [1 CMS-remark: 28122K(49152K)] 29959K(63936K), 0.0010248 secs] [Times: user=0.00 sys=0.00, real=0.00 secs]1.702: [CMS-concurrent-sweep-start]1.739: [CMS-concurrent-sweep: 0.035/0.037 secs] [Times: user=0.11 sys=0.02, real=0.05 secs]1.739: [CMS-concurrent-reset-start]1.741: [CMS-concurrent-reset: 0.001/0.001 secs] [Times: user=0.00 sys=0.00, real=0.00 secs]

     

  2.  

CMS收集器特点:

尽可能降低停顿
会影响系统整体吞吐量和性能

  • 比如,在用户线程运行过程中,分一半CPU去做GC,系统性能在GC阶段,反应速度就下降一半

清理不彻底 

  • 因为在清理阶段,用户线程还在运行,会产生新的垃圾,无法清理

因为和用户线程一起运行,不能在空间快满时再清理(因为也许在并发GC的期间,用户线程又申请了大量内存,导致内存不够) 

  • -XX:CMSInitiatingOccupancyFraction设置触发GC的阈值
  • 如果不幸内存预留空间不够,就会引起concurrent mode failure
 
  1. 33.348: [Full GC 33.348: [CMS33.357: [CMS-concurrent-sweep: 0.035/0.036 secs] [Times: user=0.11 sys=0.03, real=0.03 secs](concurrent mode failure): 47066K->39901K(49152K), 0.3896802 secs] 60771K->39901K(63936K), [CMS Perm : 22529K->22529K(32768K)], 0.3897989 secs] [Times: user=0.39 sys=0.00, real=0.39 secs]

     

一旦 concurrent mode failure产生,将使用串行收集器作为后备。

CMS也提供了整理碎片的参数:

-XX:+ UseCMSCompactAtFullCollection Full GC后,进行一次整理

  • 整理过程是独占的,会引起停顿时间变长

-XX:+CMSFullGCsBeforeCompaction  

  • 设置进行几次Full GC后,进行一次碎片整理

-XX:ParallelCMSThreads 

  • 设定CMS的线程数量(一般情况约等于可用CPU数量)

CMS的提出是想改善GC的停顿时间,在GC过程中的确做到了减少GC时间,但是同样导致产生大量内存碎片,又需要消耗大量时间去整理碎片,从本质上并没有改善时间。 

4. G1收集器

G1是目前技术发展的最前沿成果之一,HotSpot开发团队赋予它的使命是未来可以替换掉JDK1.5中发布的CMS收集器。

与CMS收集器相比G1收集器有以下特点:

1. 空间整合,G1收集器采用标记整理算法,不会产生内存空间碎片。分配大对象时不会因为无法找到连续空间而提前触发下一次GC。

2. 可预测停顿,这是G1的另一大优势,降低停顿时间是G1和CMS的共同关注点,但G1除了追求低停顿外,还能建立可预测的停顿时间模型,能让使用者明确指定在一个长度为N毫秒的时间片段内,消耗在垃圾收集上的时间不得超过N毫秒,这几乎已经是实时Java(RTSJ)的垃圾收集器的特征了。

上面提到的垃圾收集器,收集的范围都是整个新生代或者老年代,而G1不再是这样。使用G1收集器时,Java堆的内存布局与其他收集器有很大差别,它将整个Java堆划分为多个大小相等的独立区域(Region),虽然还保留有新生代和老年代的概念,但新生代和老年代不再是物理隔阂了,它们都是一部分(可以不连续)Region的集合。

G1的新生代收集跟ParNew类似,当新生代占用达到一定比例的时候,开始出发收集。

和CMS类似,G1收集器收集老年代对象会有短暂停顿。

步骤:

  1. 标记阶段,首先初始标记(Initial-Mark),这个阶段是停顿的(Stop the World Event),并且会触发一次普通Mintor GC。对应GC log:GC pause (young) (inital-mark)
  2. Root Region Scanning,程序运行过程中会回收survivor区(存活到老年代),这一过程必须在young GC之前完成。
  3. Concurrent Marking,在整个堆中进行并发标记(和应用程序并发执行),此过程可能被young GC中断。在并发标记阶段,若发现区域对象中的所有对象都是垃圾,那个这个区域会被立即回收(图中打X)。同时,并发标记过程中,会计算每个区域的对象活性(区域中存活对象的比例)。
  4. Remark, 再标记,会有短暂停顿(STW)。再标记阶段是用来收集 并发标记阶段 产生新的垃圾(并发阶段和应用程序一同运行);G1中采用了比CMS更快的初始快照算法:snapshot-at-the-beginning (SATB)。
  5. Copy/Clean up,多线程清除失活对象,会有STW。G1将回收区域的存活对象拷贝到新区域,清除Remember Sets,并发清空回收区域并把它返回到空闲区域链表中。
  6. 复制/清除过程后。回收区域的活性对象已经被集中回收到深蓝色和深绿色区域。

5. 安全点

GC的停顿主要来源于可达性分析上,程序执行时并非在所有地方都能停顿下来开始GC,只有在到达安全点时才能暂停。

安全点的选定基本上是以程序“是否具有让程序长时间执行的特征”为标准进行选定的——因为每条指令执行的时间都非常短暂,程序不太可能因为指令流长度太长这个原因而过长时间运行,“长时间执行”的最明显特征就是指令序列复用,例如方法调用、循环跳转、异常跳转等,所以具有这些功能的指令才会产生安全点。

接下来的问题就在于,如何让程序在需要GC时都跑到安全点上停顿下来,大多数JVM的实现都是采用主动式中断的思想。

主动式中断的思想是当GC需要中断线程的时候,不直接对线程操作,仅仅简单地设置一个标志,各个线程执行时主动去轮询这个标志,发现中断标志为真时就自己中断挂起,轮询标志的地方和安全点是重合的,另外再加上创建对象需要分配内存的地方。

其他:

只要记住流行的组合就这几种情况
Serial  一般情况
ParNew + CMS 
ParallelYoung + ParallelOld
G1GC

-------------------------------

如果是吞吐量优先,可以考虑Parrallel Scavenge和Parrallel Old垃圾回收器组合;这种一般出现在科学计算、数据挖掘、thrput等场景。如果是响应时间优先,那么要考虑JDK的版本,如果是JDK1.8那么可以使用G1,或者ParNew和CMS垃圾回收器组合(效果比G1要差一点);这种一般出现在网页GUI、API等场景。

股票日均百万交易系统 JVM堆栈大小设置与调优
热力站亿级别流量系统堆内年轻代与老年代回收设置与调优
高并发系统如果使用G1垃圾回收优化性能
每秒10万并发秒杀系统为什么会频繁发生GC
订单年结算 严重full GC导致系统卡死
线上OOM监控及定位与解决

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/386550.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

灵魂拷问!一起刷完了这份1307页的安卓面试宝典吧,不吃透都对不起自己

前言 每个程序员都有一个梦想,那就是进一线互联网公司深造,不要跟我说你不想进去,如果给你一个这样的平台,不管是薪资待遇还是接触的高度来说,对我们程序员来说都是一个机会,我以前有一个同事,…

ShardingSphere分库分表实战

ShardingSphere是一套开源的分布式数据库中间件解决方案组成的生态圈,它由Sharding-JDBC、Sharding-Proxy和Sharding-Sidecar(计划中)这3款相互独立的产品组成。 他们均提供标准化的数据分片、分布式事务和数据库治理功能,可适用于…

灵魂拷问!细数Android开发者的艰辛历程,成功入职阿里

什么是中年危机 根据权威数据显示,国内IT程序员鼎盛时期是在25-27岁左右,30岁对于程序员而言完全是一个38线,接着就是转业转岗的事情,这一点在业界也算是一个共识了。 大学毕业步入IT行业普遍年龄也是在22岁左右,然而…

JMM模型到并发编程

电脑:内存 L1 L2 L3 缓存 CPU ctrlatldel就可以看到 Java 有线程内存,在执行线程的时候,会从主内存把变量加载到工作内存(缓存),所以,在多线程同时改变一个静态变量时候,实际是分开…

焦虑的移动互联网开发者如何破局?专题解析

尴尬的35岁 不知道是哪个人提出的职场35岁就要面临被淘汰的定律,因为35岁定律本来就是个伪命题,尤其是在IT行业! 现在年八九百万的大学生毕业,他们虽然年轻活力,但是很多企业也将之“拒之门外”。 35岁的不要,二十几…

17.前端路由router-07keep-alive

keep-alive是Vue提供的一个抽象组件,用来对组件进行缓存,从而节省性能, 由于是一个抽象组件,所以在v页面渲染完毕后不会被渲染成一个DOM元素 当组件在keep-alive内被切换时组件的activated、deactivated这两个生命 周期钩子函数会…

使用IDEA创建Maven项目和Maven使用入门(配图详解)

本文详解的讲解了使用IDEA创建Maven项目,及Maven的基础入门。 1、打开IDEA,右上角选择File->New->Project 2、如图中所示选择Maven(可按自己所需添加,否则加载时速度很慢) 3、添加项目所需Groupld,ArtifactId,Ve…

jvisualvm安装Visual GC插件

给jdk自带的jvisualvm安装Visual GC插件,遇到Were sorry the java.net site has closed(我们很抱歉java.net网站已经关闭) 1、找到新的更新地址 visualvm新访问地址:https://visualvm.github.io/index.html 进入“Plugins”&…

来自阿里巴巴佛系安卓程序员的指南,专题解析

开头 中国互联网发展的这些年,如今90后程序员是中国程序员的主力军,互联网的热潮也让一批批00后蠢蠢欲动,尝试涌入互联网圈。 当程序员容易,当一个优秀的程序员需要不断学习,从初级程序员到高级程序员,从…

C#在WinForm中打开控制台显示

引用: namespace 测试使用 {public partial class Form1 : Form{[System.Runtime.InteropServices.DllImport("kernel32.dll", SetLastError true)][return: System.Runtime.InteropServices.MarshalAs(System.Runtime.InteropServices.UnmanagedType.Bo…

Redis+AQS

前言 对于java的单进程应用来说,存在资源竞争的场景可以使用synchronized关键字和Lock来对资源进行加锁,使整个操作具有原子性。但是对于多进程或者分布式的应用来说,上面提到的锁不共享,做不到互相通讯,所以就需要分…

disruptor 介绍

一、背景 1.来源 Disruptor是英国外汇交易公司LMAX开发的一个高性能队列,研发的初衷是解决内部的内存队列的延迟问题,而不是分布式队列。基于Disruptor开发的系统单线程能支撑每秒600万订单,2010年在QCon演讲后,获得了业界关注。…

算法题+JVM+自定义View,详细的Android学习指南

前言 想要成为一名优秀的Android开发,你需要一份完备的知识体系,在这里,让我们一起成长为自己所想的那样~。 学算法真的很痛苦,虽然大数据现在很火,但找到适合自己定位的职业也未尝不是一种合理选择。 投百度的经历非…

用过的前端插件合集

用过的前端插件合集 FontAwesome字体 Font Awesome详细用法参见上述站点的Examples。 SweetAlert系列 SweetAlertSweetAlert2SweetAlert 到 SweetAlert2 升级指南示例: 基本使用: swal("标题","内容","success);使用SweetAlert…

CAS和AQS

CAS 全称(Compare And Swap),比较交换 Unsafe类是CAS的核心类,提供硬件级别的原子操作。 // 对象、对象的地址、预期值、修改值 public final native boolean compareAndSwapInt(Object var1, long var2, int var4, int var5);缺点&#xf…

系统盘点Android开发者必须掌握的知识点,全网疯传

最近在知乎上,有许多人在邀请我去回答“Android前景怎么样、是不是要凉了、是不是应该考虑要转行?”等一系列的问题。 想着可能有很多人都有这样的担心,于是就赶紧写篇文章,来跟你们谈下Android开发的前景到底怎么样?…

数据库操作DDL

show database; 查看所有数据库 drop database db_name; 删除数据库 create database db_name;创建数据库 一个数据库对应一个文件夹 create database if not exists db_name; show warnings; 查看所有警告 show create databae db_name;查看创建的数据库 create database if n…

细数Android开发者的艰辛历程,已拿offer附真题解析

笼统来说,中年程序员容易被淘汰的原因其实不外乎三点。 1、输出能力已到顶点。这个人奋斗十来年了,依旧碌碌无为,很明显这人的天花板就这样了,说白了,天赋就这样。 2、适应能力越来越差。年纪大,有家庭&…

原子操作类AtomicInteger详解

为什么需要AtomicInteger原子操作类? 对于Java中的运算操作,例如自增或自减,若没有进行额外的同步操作,在多线程环境下就是线程不安全的。num解析为numnum1,明显,这个操作不具备原子性,多线程并…

移动端Rem之讲解总结

日妈常说的H5页面,为啥叫H5页面嘛,不就是手机上展示的页面吗?那是因为啊手机兼容所有html5新特性,所以跑在手机上的页面也叫h5页面,跨平台(安装ios),基于webview,它就是终端开发的一个组件&…