JVM内存分配策略
总的来说,JVM管理的内存包括堆内存和非堆内存。堆就是Java代码可及的内存,是留给开发人员使用的;非堆就是JVM留给自己用的,所以方法区、JVM内部处理或优化所需的内存(如JIT编译后的代码缓存)、每个类结构(如运行时常数池、字段和方法数据)以及方法和构造方法的代码都在非堆内存中。
因此这里所说的内存分配是指堆内存的分配,即我们程序中生成的对象的分配。以下所述针对的是HotSpot虚拟机。
1、Java堆结构
以HotSpot为例,如下图:
1.1、年轻代
年轻代(或称新生代,Young、New)通常用来放新生成的对象(但不绝对,如可以通过-XX:PretenureSizeThreadshold配置将大对象直接分配在老年代,仅对Serial和ParNew收集器有效)。年轻代的目标就是尽可能快速地收集掉那些生命周期短的对象。
年轻代分3个区,1个Eden区,2个Survivor区(from 和 to),但每次只使用Eden和一个Survivor区,另一个Survivor区空着。空Survivor区用来放MinorGC时从Eden和在使用的Survivor区中复制来的活着的对象。
针对年轻代的GC为Minor GC或称Young GC,在Eden剩余空间不足以分配新对象时触发
1.2、老年代
老年代(Old、Tenure)通常用来存放从年轻代复制过来的对象(也可直接在老年代分配对象)。老年代中存放的是一些生命周期较长的对象。
针对老年代的GC为Major GC或称Full GC,在老年代剩余空间不足以容纳新对象时触发。Major GC经常会伴随至少一次的Minor GC(但非绝对,如下面所说的HandlePromotionFailure策略,有可能直接进行Major GC;Parallel Scavenge收集器提供了直接进行Major GC的策略选择),Major GC一般比Minor GC慢10倍以上。
永久代
通常还可以听到永久代(PermGen space)的概念,其实它并不在Java堆。有时永久代又被称为元空间(Metaspace)或方法区,比较乱。它们的区别是:方法区为JVM的规范,永久代、元空间分别是方法区在HotSpot中的一种实现,对于其他类型的虚拟机实现,如 JRockit(BEA)、J9(IBM),其并没有这些概念。
2、堆内存分配过程
对象的内存分配,绝大部分都是在堆上分配(少数经过JIT编译后被拆散为标量类型并间接在栈上分配),这里介绍在堆上的分配。
生成对象(为对象分配内存)的过程如下:
- 首先看Eden剩余空间是否足够分配该对象,若够则直接在Eden分配;
- 否则进行MinorGC:将Eden和在使用的Survivor区中活着的对象复制到另一个Survivor区,并回收Eden和使用着的Survivor区。然后把对象分配到Eden,以后另一个Survivor成为使用的Survivor区;
- 若另一个Survivor区不能完全容纳复制过来的对象,则能放下的放入该Survivor,把放不下的放到老年代(即进行分配担保);
- 若老年代剩余空间不够了则进行Full GC,
- 若Full GC后仍不够则抛出OOM异常。
具体可以分为:
- 分配过程(优先在Eden分配,分配不了则执行MinorGC)
- 分配担保(MinorGC后若Survivor放不下的存活对象移到老年代,老年代仍不够则进行MajorGC,MajorGC后仍不够则OOM异常)
- 提前移动的配置(大对象、对象年龄、动态年龄)
以下示例所用JDK为1.8.0_45。GC日志格式含义见理解GC日志
2.1、对象优先在Eden区分配
对象优先分配在Eden区,如果Eden区没有足够的空间时,虚拟机执行一次Minor GC。
示例代码:
package cn.edu.buaa.jvmbook; /**
* @author zsm
* @date 2017年1月2日 下午10:33:12
*/
/*
* 代码3-5
-Xms20M -Xmx20M -Xmn10M
-XX:+UseSerialGC(client模式运行,收集器为Serail+SerialOld)
-XX:+PrintGCDetails
-XX:SurvivorRatio=8
*
*/ public class _3_5_YoungGeneration_MinorGC {
private static final int _1MB = 1024 * 1024; public static void main(String[] args) {
// TODO Auto-generated method stub
byte[] allocation1, allocation2, allocation3, allocation4;
allocation1 = new byte[2 * _1MB];
allocation2 = new byte[2 * _1MB];
allocation3 = new byte[2 * _1MB];
allocation4 = new byte[4 * _1MB];// 出现一次MinorGC
}
}
GC日志:
[GC (Allocation Failure) [DefNew: 7291K->508K(9216K), 0.0035043 secs] 7291K->6652K(19456K), 0.0035385 secs] [Times: user=0.00 sys=0.00, real=0.00 secs]
Heap
def new generation total 9216K, used 4687K [0x00000000fec00000, 0x00000000ff600000, 0x00000000ff600000)
eden space 8192K, 51% used [0x00000000fec00000, 0x00000000ff014930, 0x00000000ff400000)
from space 1024K, 49% used [0x00000000ff500000, 0x00000000ff57f390, 0x00000000ff600000)
to space 1024K, 0% used [0x00000000ff400000, 0x00000000ff400000, 0x00000000ff500000)
tenured generation total 10240K, used 6144K [0x00000000ff600000, 0x0000000100000000, 0x0000000100000000)
the space 10240K, 60% used [0x00000000ff600000, 0x00000000ffc00030, 0x00000000ffc00200, 0x0000000100000000)
Metaspace used 2559K, capacity 4486K, committed 4864K, reserved 1056768K
class space used 274K, capacity 386K, committed 512K, reserved 1048576K
说明:新生代可用的空间为9M = 8M(Eden容量) + 1M(一个survivor容量),分配完allocation1、allocation2、allocation3之后,无法再分配allocation4,会发生分配失败,则需要进行一次Minor GC,survivor to区域的容量为1M,无法容纳总量为6M的三个对象,则会通过担保机制将allocation1、allocation2、allocation3转移到老年代,然后再将allocation4分配在Eden区。
2.2、空间分配担保
空间分配担保(Handle Promotion,意译成对象存储位置晋升还差不多,分配担保...什么鬼)即让老年代空间来存放年轻代中的对象,其前提是老年代还有容纳的空间。
在发生Minor GC时,虚拟机会检查老年代连续的空闲区域是否大于新生代所有对象的总和,若成立,则说明Minor GC是安全的,否则,虚拟机需要查看HandlePromotionFailure的值,看是否允许担保失败,若允许,则虚拟机继续检查老年代最大可用的连续空间是否大于历次晋升到老年代对象的平均大小,若大于,将尝试进行一次Minor GC;若小于或者HandlePromotionFailure设置不运行冒险,那么此时将改成一次Full GC。
以上是JDK Update 24之前的策略,之后的策略改变了,只要老年代的连续空间大于新生代对象总大小或者历次晋升的平均大小就会进行Minor GC,否则将进行Full GC。
冒险是指经过一次Minor GC后有大量对象存活,而新生代的survivor区很小,放不下这些大量存活的对象,所以需要老年代进行分配担保,把survivor区无法容纳的对象直接进入老年代。
该策略的意义之一在于减少不必要的MinorGC。具体的流程图如下:
示例代码:
/**
*
*/
package cn.edu.buaa.jvmbook; /**
* @author zsm
* @date 2017年1月5日 下午3:31:38
*/
public class _3_9_HandlePrpmotion {
private static final int _1MB = 1024 * 1024; /*
* 代码3-9 -Xms20M -Xmx20M -Xmn10M -XX:SurvivorRatio=8 -XX:+PrintGCDetails -XX:+UseSerialGC -XX:+HandlePromotionFailure
*/
/*
-Xms20M -Xmx20M -Xmn10M
-XX:SurvivorRatio=8
-XX:+PrintGCDetails
-XX:+UseSerialGC
-XX:-HandlePromotionFailure
*/
public static void main(String[] args) {
// TODO Auto-generated method stub
byte[] allocation1, allocation2, allocation3, allocation4, allocation5, allocation6, allocation7, allocation8;
allocation1 = new byte[2 * _1MB];
allocation2 = new byte[2 * _1MB];
allocation3 = new byte[2 * _1MB];
allocation1 = null;
allocation4 = new byte[2 * _1MB];
allocation5 = new byte[2 * _1MB];
allocation6 = new byte[2 * _1MB];
allocation4 = null;
allocation5 = null;
allocation6 = null;
allocation7 = new byte[2 * _1MB];
} }
GC日志(没在老JDK上跑,可能与期望的有点出入):
[GC (Allocation Failure) [DefNew: 7291K->508K(9216K), 0.0042361 secs] 7291K->4604K(19456K), 0.0042750 secs] [Times: user=0.00 sys=0.00, real=0.00 secs]
[GC (Allocation Failure) [DefNew: 6811K->508K(9216K), 0.0007200 secs] 10907K->4604K(19456K), 0.0007436 secs] [Times: user=0.00 sys=0.00, real=0.00 secs]
Heap
def new generation total 9216K, used 2638K [0x00000000fec00000, 0x00000000ff600000, 0x00000000ff600000)
eden space 8192K, 26% used [0x00000000fec00000, 0x00000000fee14930, 0x00000000ff400000)
from space 1024K, 49% used [0x00000000ff400000, 0x00000000ff47f0e0, 0x00000000ff500000)
to space 1024K, 0% used [0x00000000ff500000, 0x00000000ff500000, 0x00000000ff600000)
tenured generation total 10240K, used 4096K [0x00000000ff600000, 0x0000000100000000, 0x0000000100000000)
the space 10240K, 40% used [0x00000000ff600000, 0x00000000ffa00020, 0x00000000ffa00200, 0x0000000100000000)
Metaspace used 2560K, capacity 4486K, committed 4864K, reserved 1056768K
class space used 274K, capacity 386K, committed 512K, reserved 1048576K
说明:
发生了两Minor次GC,第一次发生在给allocation4分配内存空间时,由于老年代的连续可用空间大于存活的对象总和,所以allocation2、allocation3将会进入老年代,allocation1的空间将被回收,allocation4分配在新生代;第二次发生在给allocation7分配内存空间时,此次GC将allocation4、allocation5、allocation6所占的内存全部回收。最后,allocation2、allocation3在老年代,allocation7在新生代。
2.3、大对象直接进入老年代
需要大量连续内存空间的Java对象称为大对象,大对象的出现会导致提前触发垃圾收集以获取更大的连续的空间来进行大对象的分配。虚拟机提供了-XX:PretenureSizeThreadshold(仅对Serial和ParNew收集器有效)参数来设置大对象的阈值,超过阈值的对象直接分配到老年代。这样做的目的是避免在Eden区和两个 Survivor区之间发生大量的内存拷贝(新生代采用复制算法收集内存)。
示例代码:
package cn.edu.buaa.jvmbook; /**
* @author zsm
* @date 2017年1月2日 下午11:08:58
* @version 1.0
* @parameter
* @return
*/
/*
* 代码3-6 -Xms20M -Xmx20M -Xmn10M -XX:+UseSerialGC(client模式运行,收集器为Serail+SerialOld) -XX:+PrintGCDetails -XX:SurvivorRatio=8 -XX:PretenureSizeThreshold=3145728(3M,此参数只能以字节为单位)
*
*/
// -XX:PretenureSizeThreshold=3145728参数,大对象直接进入老年代,参数只对Serial和ParNew两种收集器有效
public class _3_6_BigObjectOldGeneration {
private static final int _1MB = 1024 * 1024; public static void main(String[] args) {
// TODO Auto-generated method stub
byte[] allocation1 = new byte[4 * _1MB];// 出现一次MinorGC } }
GC日志:
Heap
def new generation total 9216K, used 1311K [0x00000000fec00000, 0x00000000ff600000, 0x00000000ff600000)
eden space 8192K, 16% used [0x00000000fec00000, 0x00000000fed47f80, 0x00000000ff400000)
from space 1024K, 0% used [0x00000000ff400000, 0x00000000ff400000, 0x00000000ff500000)
to space 1024K, 0% used [0x00000000ff500000, 0x00000000ff500000, 0x00000000ff600000)
tenured generation total 10240K, used 4096K [0x00000000ff600000, 0x0000000100000000, 0x0000000100000000)
the space 10240K, 40% used [0x00000000ff600000, 0x00000000ffa00010, 0x00000000ffa00200, 0x0000000100000000)
Metaspace used 2559K, capacity 4486K, committed 4864K, reserved 1056768K
class space used 274K, capacity 386K, committed 512K, reserved 1048576K
说明:4MB对象超过PretenureSizeThreshold阈值(3MB),直接分配在了老年代。
2.4、长期存活的对象进入老年代
每个对象有一个对象年龄计数器,与对象头标记字中的GC分代年龄对应。对象出生在Eden区、经过一次Minor GC后仍然存活,并能够被Survivor容纳,设置年龄为1,对象在Survivor区每次经过一次Minor GC,年龄就加1,当年龄达到一个阈值(默认15),下次触发Minor GC时就被移到老年代(即配置的是最多被在Survivor间移动几次,达到阈值后下一次GC时不移动而是直接晋升了)。虚拟机提供了-XX:MaxTenuringThreshold来进行设置。
示例代码:
package cn.edu.buaa.jvmbook; /**
* @author zsm
* @date 2017年1月2日 下午11:19:41
* @version 1.0
* @parameter
* @return
*/
/*
* 代码3-7 -Xms20M -Xmx20M -Xmn10M -XX:+UseSerialGC(client模式运行,收集器为Serail+SerialOld) -XX:+PrintGCDetails -XX:SurvivorRatio=8 -XX:MaxTenuringThreshold=1 -XX:+PrintTenuringDistribution
*
*/ // -XX:MaxTenuringThreshold用来调节对象在Survivor中“熬过”多少次MinorGC后进入老年代
public class _3_7_LongLiveOldGeneration {
private static final int _1MB = 1024 * 1024;
/*
-Xms20M -Xmx20M -Xmn10M
-XX:+UseSerialGC
-XX:+PrintGCDetails
-XX:SurvivorRatio=8
-XX:MaxTenuringThreshold=1
-XX:+PrintTenuringDistribution
*/
public static void main(String[] args) {
// TODO Auto-generated method stub
byte[] allocation1, allocation2, allocation3;
allocation1 = new byte[_1MB / 4];
// 何时进入老年代取决于XX:MaxTenuringThreshold设置
allocation2 = new byte[4 * _1MB];
allocation3 = new byte[4 * _1MB];
allocation3 = null;
allocation3 = new byte[4 * _1MB];
} }
GC日志:
[GC (Allocation Failure) [DefNew Desired survivor size 524288 bytes, new threshold 1 (max 1)- age 1: 783256 bytes, 783256 total: 5499K->764K(9216K), 0.0024536 secs] 5499K->4860K(19456K), 0.0024878 secs] [Times: user=0.00 sys=0.00, real=0.00 secs]
[GC (Allocation Failure) [DefNew Desired survivor size 524288 bytes, new threshold 1 (max 1): 4860K->0K(9216K), 0.0006581 secs] 8956K->4860K(19456K), 0.0006864 secs] [Times: user=0.00 sys=0.00, real=0.00 secs]
Heap
def new generation total 9216K, used 4178K [0x00000000fec00000, 0x00000000ff600000, 0x00000000ff600000)
eden space 8192K, 51% used [0x00000000fec00000, 0x00000000ff014930, 0x00000000ff400000)
from space 1024K, 0% used [0x00000000ff400000, 0x00000000ff400000, 0x00000000ff500000)
to space 1024K, 0% used [0x00000000ff500000, 0x00000000ff500000, 0x00000000ff600000)
tenured generation total 10240K, used 4860K [0x00000000ff600000, 0x0000000100000000, 0x0000000100000000)
the space 10240K, 47% used [0x00000000ff600000, 0x00000000ffabf120, 0x00000000ffabf200, 0x0000000100000000)
Metaspace used 2560K, capacity 4486K, committed 4864K, reserved 1056768K
class space used 274K, capacity 386K, committed 512K, reserved 1048576K
说明:发生了两次Minor GC,第一次是在给allocation3进行分配的时候会出现一次Minor GC,此时survivor区域不能容纳allocation2,但是可以容纳allocation1,所以allocation1将会进入survivor区域并且年龄为1,达到了阈值,将在下一次GC时晋升到老年代,而allocation2则会通过担保机制进入老年代。第二次发生GC是在第二次给allocation3分配空间时,这时,allocation1的晋升到老年代,此次GC也可以清理出原来allocation3占据的4MB空间,将allocation3分配在Eden区。所以,最后的结果是allocation1、allocation2在老年代,allocation3在Eden区。
2.5、动态判断对象年龄
对象的年龄到达了MaxTenuringThreshold可以进入老年代,同时,如果在survivor区中相同年龄所有对象大小的总和大于survivor区的一半,年龄大于等于该年龄的对象就可以直接进入老年代。无需等到MaxTenuringThreshold中要求的年龄。
示例代码:
/**
*
*/
package cn.edu.buaa.jvmbook; /**
* @author zsm
* @date 2017年1月5日 下午3:00:16
*/
/**
* @author zsm
*
*/
public class _3_8_DynamicObjectAgeJudge { private static final int _1MB = 1024 * 1024; /*
* 代码3-8 -Xms20M -Xmx20M -Xmn10M -XX:SurvivorRatio=8 -XX:+PrintGCDetails -XX:+UseSerialGC -XX:MaxTenuringThreshold=15 -XX:+PrintTenuringDistribution
*/
/*
-Xms20M -Xmx20M -Xmn10M
-XX:SurvivorRatio=8
-XX:+PrintGCDetails
-XX:+UseSerialGC
-XX:MaxTenuringThreshold=15
-XX:+PrintTenuringDistribution
*/
public static void main(String[] args) {
// TODO Auto-generated method stub
byte[] allocation1, allocation2, allocation3, allocation4;
allocation1 = new byte[_1MB / 4];
allocation2 = new byte[_1MB / 4];
allocation3 = new byte[4 * _1MB];
allocation4 = new byte[4 * _1MB];
allocation4 = null;
allocation4 = new byte[4 * _1MB];
} }
GC日志:
[GC (Allocation Failure) [DefNew Desired survivor size 524288 bytes, new threshold 1 (max 15)- age 1: 1045416 bytes, 1045416 total: 5755K->1020K(9216K), 0.0027553 secs] 5755K->5116K(19456K), 0.0028017 secs] [Times: user=0.00 sys=0.02, real=0.00 secs]
[GC (Allocation Failure) [DefNew Desired survivor size 524288 bytes, new threshold 15 (max 15): 5116K->0K(9216K), 0.0009216 secs] 9212K->5116K(19456K), 0.0009399 secs] [Times: user=0.00 sys=0.00, real=0.00 secs]
Heap
def new generation total 9216K, used 4178K [0x00000000fec00000, 0x00000000ff600000, 0x00000000ff600000)
eden space 8192K, 51% used [0x00000000fec00000, 0x00000000ff014930, 0x00000000ff400000)
from space 1024K, 0% used [0x00000000ff400000, 0x00000000ff400000, 0x00000000ff500000)
to space 1024K, 0% used [0x00000000ff500000, 0x00000000ff500000, 0x00000000ff600000)
tenured generation total 10240K, used 5116K [0x00000000ff600000, 0x0000000100000000, 0x0000000100000000)
the space 10240K, 49% used [0x00000000ff600000, 0x00000000ffaff130, 0x00000000ffaff200, 0x0000000100000000)
Metaspace used 2559K, capacity 4486K, committed 4864K, reserved 1056768K
class space used 274K, capacity 386K, committed 512K, reserved 1048576K
说明:发生了两次Minor GC,第一次发生在给allocation4分配内存时,此时allocation1、allocation2将会进入survivor区,而allocation3通过担保机制将会进入老年代。第二次发生在第二次给allocation4分配内存时,此时,survivor区的allocation1、allocation2达到了survivor区容量的一半,将会进入老年代,此次GC可以清理出allocation4原来的4MB空间,并将allocation4分配在Eden区。最终,allocation1、allocation2、allocation3在老年代,allocation4在Eden区。、
3、堆内存分配参数设置
见 HotSpot JVM各区域内存分配参数设置-MarchOn
- -Xmx3550m:等价于-XX:MaxHeapSize,设置JVM最大堆内存为3550M。
- -Xms3550m:等价于-XX:InitialHeapSize,设置JVM初始堆内存为3550M。此值可以设置与-Xmx相同,以避免每次垃圾回收完成后JVM重新分配内存。
- -XX:NewSize=1024m:设置年轻代初始值为1024M。
- -XX:MaxNewSize=1024m:设置年轻代最大值为1024M。
- -Xmn2g:设置年轻代大小为2G,相当于将上面两个都设为2G。在整个堆内存大小确定的情况下,增大年轻代将会减小年老代,反之亦然。此值关系到JVM垃圾回收,对系统性能影响较大,官方推荐配置为整个堆大小的3/8。
- -XX:SurvivorRatio=4:设置年轻代中Eden区与一个Survivor区的比值。表示Edgen为一个Survivor的4倍,即1个Survivor区占整个年轻代大小的1/6。默认为8。
- -XX:NewRatio=4:设置老年代与年轻代(包括1个Eden和2个Survivor区)的比值。表示老年代是年轻代的4倍。若按官方推荐年轻代占整个堆空间3/8,则对应这里的值为5/3
- -XX:PretenureSizeThreadshold=1024:设置让大于此阈值的对象直接分配在老年代(只对Serial、ParNew收集器有效),单位为字节
- -XX:MaxTenuringThreshold=7:表示一个对象如果在Survivor区移动了7次那下次MinorGC时就进入老年代。如果设置为0的话,则年轻代对象不经过Survivor区,直接进入年老代,对于需要大量常驻内存的应用,这样做可以提高效率。如果将此值设置为一个较大值,则年轻代对象会在Survivor区进行多次复制,这样可以增加对象在年轻代存活时间,增加对象在年轻代被垃圾回收的概率,减少Full GC的频率,可以在某种程度上提高服务稳定性。
4、参考资料
[1]《深入理解Java虚拟机——JVM高级特性与最佳实践》
[2]http://www.cnblogs.com/leesf456/p/5218594.html
[3]Java堆内存设置原理
JVM内存分配策略的更多相关文章
- 深入理解JVM内存分配策略
理解JVM内存分配策略 三大原则+担保机制 JVM分配内存机制有三大原则和担保机制 具体如下所示: 优先分配到eden区 大对象,直接进入到老年代 长期存活的对象分配到老年代 空间分配担保 对象优先在 ...
- JVM内存分配策略,及垃圾回收算法
本人免费整理了Java高级资料,一共30G,需要自己领取;传送门:https://mp.weixin.qq.com/s/JzddfH-7yNudmkjT0IRL8Q 说起垃圾收集(Garbage Co ...
- JVM内存分配策略、各个代区、FullGC/MinorGC
主要讨论默认的Serial/Serial Old内存分配: 一.几种分配方案 1. 对象优先在Eden分配: 一般情况下,对象会在新生代的Eden区分配,Eden区没有足够空间时,虚拟机会 发起一次 ...
- 深入了解java虚拟机(JVM) 第七章 内存分配策略
理解了jvm内存分配策略不仅是程序性能调优的重要知识,还能够给养成自己一种良好的代码思路,一个程序的代码差异往往都是在这里体现出来的. 一.对象优先分配到Eden区域 一般来说,新创建的对象都会直 ...
- GC之一--GC 的算法分析、垃圾收集器、内存分配策略介绍
一.概述 垃圾收集 Garbage Collection 通常被称为“GC”,它诞生于1960年 MIT 的 Lisp 语言,经过半个多世纪,目前已经十分成熟了. jvm 中,程序计数器.虚拟机栈.本 ...
- JVM内存分配和垃圾回收以及性能调优
JVM内存分配策略 一:堆中优先分配Eden 大多数情况下,对象都在新生代的Eden区中分配内存.而新生代会频繁进行垃圾回收. 二:大对象直接进入老年代 需要大量连续空间的对象,如:长字符串.数组等, ...
- JVM学习总结四——内存分配策略
之前几篇我们介绍了jvm的内存模型以及垃圾回收机制,而本篇我们将介绍几个JVM中对象在分配内存是应该遵循的策略.毕竟,想要去优化程序,不仅要考虑垃圾回收的过程,还要从对象内存分配的角度减少gc的代价. ...
- java虚拟机学习-JVM内存管理:深入垃圾收集器与内存分配策略(4)
Java与C++之间有一堵由内存动态分配和垃圾收集技术所围成的高墙,墙外面的人想进去,墙里面的人却想出来. 概述: 说起垃圾收集(Garbage Collection,下文简称GC),大部分人都把这项 ...
- jvm系列 (二) ---垃圾收集器与内存分配策略
垃圾收集器与内存分配策略 前言:本文基于<深入java虚拟机>再加上个人的理解以及其他相关资料,对内容进行整理浓缩总结.本文中的图来自网络,感谢图的作者.如果有不正确的地方,欢迎指出. 目 ...
随机推荐
- java 执行 jar 包中的 main 方法
java 执行 jar 包中的 main 方法 通过 OneJar 或 Maven 打包后 jar 文件,用命令: java -jar ****.jar执行后总是运行指定的主方法,如果 jar 中有多 ...
- 4、项目的培训 - PMO项目管理办公室
培训是一个重要的内容,在公司内部就有相关的培训.对于PMO项目管理办公室来说,就是相关的项目的技术和业务的培训,以期让项目组人员能够快速的学习好项目业务内容和所需要使用到的技术内容,然后尽快的进入项目 ...
- 转:IE兼容模式下 SCRIPT1028: 缺少标识符、字符串或数字
IE兼容模式下 SCRIPT1028: 缺少标识符.字符串或数字例如下面一段代码 var a = { x: 1, y: 2,};alert(a.x);如果在IE的兼容性视图(IE7文档模式 ...
- 前端开发--ppt展示页面跳转逻辑实现
1. 工程地址:https://github.com/digitalClass/web_page 网站发布地址: http://115.28.30.25:8029/ 2. 今天遇到一个小问题, 同组的 ...
- JAVA NIO Socket通道
DatagramChannel和SocketChannel都实现定义读写功能,ServerSocketChannel不实现,只负责监听传入的连接,并建立新的SocketChannel,本身不传输数 ...
- [python]爬虫学习(三)糗事百科
import requestsimport osfrom bs4 import BeautifulSoupimport timepage=2url='http://www.qiushibaike.co ...
- win7系统c盘瘦身,去虚拟内存方式
电脑使用过程中,C盘出现个情况,c盘属性上的大小 > c盘内容加起来的大小 原因就是"虚拟内存"在作祟. 运行 powercfg -h off 关闭系统休眠,删除C盘 hi ...
- UOJ #221 【NOI2016】 循环之美
题目链接:循环之美 这道题感觉非常优美--能有一个这么优美的题面和较高的思维难度真的不容易-- 为了表示方便,让我先讲一下两个符号.\([a]\)表示如果\(a\)为真,那么返回\(1\),否则返回\ ...
- 唯物 VS 唯心
对于唯物和唯心,我了解的并不多.我所知道的那点皮毛,也只是源于教课书.只是近来恋上了阳明大哥,而在某年的高考模拟题中,阳明竟被作为唯心主义的代表,供考生们批判.这一批搞得我着实不爽,决定要为他平反 ...
- [LeetCode] Find K Pairs with Smallest Sums 找和最小的K对数字
You are given two integer arrays nums1 and nums2 sorted in ascending order and an integer k. Define ...