首先在github上下载mysql-connector-cpp git clone https://github.com/mysql/mysql-connector-cpp.git git上面有两个分支,2.0版本是支持mysql作为文档存储的接口,1.1版本是支持正常的关系数据库存储接口 首先我们编译安装2.0版本,进入代码目录执行 cmake . cmake –build . –config CCC cmake –build . –target install –config CCC 到这里已经安装完毕. 然后到testapp下编译测试样例 cmake . 提示出错,WITH-CONCPP没有设置,我试了编辑/etc/profile文件,设置这个变量为/usr/local/mysql/connector-c++-2.0/,但是仍然提示没有设置,于是我将CMakeLists中的 set(WITH_CONCPP $ENV{WITH_CONCPP} CACHE PATH “MySQL Connector/C++ 2.0 install location”) 改为 set(WITH_CONCPP “/usr/local/mysql/connector-c++-2.0/” CACHE PATH “MySQL Connector/C++ 2.0 install location”) 继续cmake . 提示出错,在/usr/local/mysql/connector-c++-2.0/lib64下找不到依赖库 那么将目录下生成的 libmysqlcppconn2.so libmysqlcppconn2.so.1 libmysqlcppconn2.so.1.0 拷贝到/usr/local/mysql/connector-c++-2.0/lib64中,没有的创建一个即可。 cmake . make 在run文件夹下面生成了两个可执行文件 devapi_test xapi_test 这两个文件的区别在于,xapi_test实现了c的接口,是通过mysql的一个叫做x plugin的插件连接mysql的,而devapi则是使用了c++的接口。所以如果使用xapi接口的话,mysql安装时必须安装x plugin 接下来编译安装1.1版本,先将当前的改动都commit了,然后 git checkout 1.1, cmake . 如果出错。 报缺少boost库错误,可以 sudo apt-get install libboost-all-dev 报缺少mysql.h等错误,可以通过sudo apt-get install libmysql++-dev 然后make sudo make install 然后将生成的动态库拷贝的/usr/local/lib下 sudo cp libmysqlcppconn.so* /usr/local/lib/
第 13 页的文章列表
c++中的中文字符分割
在utf-8编码的前提下,一个字符可能占用的空间为1~4个char,由于这种不确定的字符长度导致在utf-8编码的string中,无法直接使用substr进行字符串分割。 解决的方案的关键在于利用utf-8编码的特点,utf-8的第一个字符的前缀连续为1的个数代表这个”字“占用的字符数量,当只有一个字符时,第一个字符的第一位为0。具体的说明可以参考这篇文章。http://www.ruanyifeng.com/blog/2007/10/ascii\_unicode\_and\_utf-8.html 这里主要说明怎么利用代码解决这个问题
int getUtf8CharLength(char c){
int len = 0;
if(c > 0){ //利用计算机中数字的存储特点,第一位为1为负,第一位为0为正,很容易判断
return len + 1; //第一位为0时为特殊情况,需要加1
}
while(c < 0){
len++;
c = c << 1;
}
return len;
}
std::string substrWithChinese(std::string str,unsigned int start,unsigned int length){
unsigned int i = 0; //标识前进的几个“字符”
unsigned int cursor = 0; //标识前进了几个“字”
unsigned int save = 0; //保存的字符标识
unsigned int len = str.length();
char* c = new char[len + 1];
while(str[i] != '\0'&&length > 0){
unsigned int l = getUtf8CharLength(str[i]); //获取字符长度
if(cursor >= start){
unsigned int m = l;
while(m--){
c[save++] = str[i++];
}
length--;
}else{
i+=l;
}
cursor++;
}
c[i] = '\0';
return std::string(c);
}
ubuntu eclipse mars.2Bug修复
ubuntu eclipse mars.2Bug的bug具体表现为图标异常,菜单无法正常点击切换等等,问题是因为GTK方面,将eclipse的启动方式eclipse.desktop改为一下代码
[Desktop Entry]
Name=eclipse
Comment=develop java app
Exec=env SWT_GTK3=0 /home/jiang/software/eclipse/eclipse
Icon=/home/jiang/software/eclipse/icon.xpm
Terminal=false
Type=Application
Categories=devtool
网站登录系统设计
一、前言 一个网站的登录系统可以算作是一个网站的大门,如何让这个大门足够的安全,并且又不用太复杂是一个很考验经验的工作。作为一个没有经验的新手,简单记下一点自己在做网站登录系统设计时做法。 二、前提 首先假设我们设计的网站是一个单服务器的应用,并且他有多种登录方式(邮箱,手机,用户名),以及多种登录途径(web,app)。 三、正文 1.会话状态 因为是单服务器的应用,所以不用担心多台服务器之间的会话状态转移的问题,所以为了简单,我们采用的是cookie方式,这样既不用在用户关闭浏览器后再次访问就要重新登录,也可以通过设定cookie的失效时间,来让浏览器自动在一定时间后让用户重新登录,保护用户设备丢失带来的风险。 2.登录方式 考虑到需要支持邮箱,手机或者是用户名的登录,也就是用户随意输入其中的一种以及密码都要可以登录,所以要对用户名有一定的限制,首先用户名不能重复,并且用户不能是手机或者邮箱,因此要对用户名做一些简单的限制——用户名不能为纯数字,也不能包含@符号。 3.密码存储 密码的存储是一定要足够安全的。因此对密码的存储一定要够安全。我采用的是密码+salt的方式,使用sha-256加密。 4.身份验证 身份验证上,我在cookie中填入用户id和token连接而成的字符串(称为id_token),例如24|dashdiuasdhgiuagsduigaiusdg这种形式,|符号前面是Id,后面是token,token是登录时随机生成的,在登录时会讲登录记录插入到数据库中,这条记录包括用户id,登录名(用户名,邮箱或手机中的任一种)、登录途径(web还是app)、登录时生成的token、登录时间等等,然后之后用户提交请求时都会验证cookie,将cookie中的id和token截取出来,与最新的一条该用户id的登录成功的记录的token对比,如果一致,则表示身份是对的。这种做法可以很好的防止伪造cookie。对于app来说,将这个cookie保存下来就可以一直作为登录凭证。如果遇到手机丢失,想使手机上的登录失效,重新用新手机登录一次即可。 5.多端登录的冲突解决 在4.身份验证中说到,登录的身份验证是根据最新的该用户的登录记录来判断的,所以如果用户在app上登录了,再在网站上登录则会使app的登录失效,为了解决这个问题,可以在登录时附带上登录方式的字段,那么就可以解决web端和app端的冲突问题。
linux下使用crontab进行网站内容和数据库定期备份
crontab有几个常用的命令 crontab -l 列举crontab的任务 crontab -e 编辑crontab的任务 crontab -r 删除crontab的任务 crontab -h crontab的帮助 crontab -i 删除crontab前进行提示 crontab -e进行编辑任务时会使用nano进行编辑,编辑命令如下示例。 分 时 每月的第几天 每周的周几 命令 前5个参数可以使用通配符 *
m h dom mon dow command
设置每两分钟扫描一次,清理过期记录
*/2 * * * * /usr/bin/php /var/www/poker/scan.php >> /$
设置每周二23:29分备份一次
59 23 * * 2 /bin/bash /home/back.sh 59 23 * * 2 /bin/bash /home/back.sh就是我用来定期备份的指令,主要就是配合一个shell脚本 #!/bin/bash cd /home mv backup/* oldbackup/ echo “old backup file has been moved to oldbackup folder”; cd /home/backup Now=date "+%Y-%m-%d-%H-%M-%S" File_emlog=“backup-emlog-”${Now}“.sql” mysqldump -u me -ppassword emlog > $File_emlog File_java=backup-java-$Now.sql mysqldump -u me -ppassword java > $File_java File_plan=backup-plan-$Now.sql mysqldump -u me -ppassword plan > $File_plan File_sms=backup-sms-$Now.sql mysqldump -u me -ppassword sms > $File_sms File_tu=backup-tu-$Now.sql mysqldump -u me -ppassword tu > $File_tu File_wordpress=backup-wordpress-$Now.sql mysqldump -u me -ppassword wordpress > $File_wordpress echo “your databases backup successfully completed”; #数据文件到这里备份完毕 #下面备份网站的文件 tar -czf /home/backup/back_www.tar.gz /var/www
JavaEE post Base64的图片丢失数据解决
项目中有个提交Base64编码的图片到服务器,服务器端转换成图片的二进制流存放到数据库中。在实际使用中发现,保存到数据库中图片文件有损坏。表现为前一部分二进制数据相同,到了后面就开始不同了。 一开始的步骤为:
st=>start: 准备Base64数据
op1=>operation: Post准备好的Base64数据
op2=>operation: 将数据并转换为byte[]
op3=>operation: 存储到数据库
e=>end
st->op1->op2->op3->end
为了找出问题,将post这个步骤省去,并将数据直接存成图片以便观察
st=>start: 准备Base64数据
op2=>operation: 将数据并转换为byte[]
op3=>operation: 存储成图片
e=>end
st->op2->op3->end
这一步保存的文件的大小是9.0k
st=>start: 准备Base64数据
op1=>operation: Post准备好的Base64数据
op2=>operation: 将数据并转换为byte[]
op3=>operation: 存储成图片
e=>end
st->op1->op2->op3->end
这一步保存的文件的大小是8.9k
上面两步对比可以说明数据在传输的时候出现了丢失的情况,于是我猜测是不是tomcat对post方式做了限制,发现不是。查询资料发现,Base64位数据传输的时候中间的+号容易发生丢失。解决方法是将post过来的数据先UrlEncode一下即可 发生这个问题的没有找到明确的可靠的解释,其中一片文章解释为javascript将+当做字符串连接符号处理导致丢失。
Java虚拟机学习记录(九)——类文件结构(上)
##一、前言 在Java开发中,可以通过javac将.java的源代码编译为.class的类文件。之前一直以为,只有java语言可以编译为.class。但是在前些天的学习中,了解到不仅仅是Java语言可以编译成.class文件然后运行在Java虚拟机上,Clojure、Groovy、JRuby、Jython、Scala等语言都可以运行在Java虚拟机上。觉得这真是太神奇了。今天这一章的内容刚好可以解释这些。 ##二、Java虚拟机的无关系特点 一般都说Java是平台无关的,因为Java是运行在Java虚拟机上的,而Java虚拟机是开发成各个平台通用的。那么同时,Java虚拟机其实也是语言无关的,也就是说,Java虚拟机并不要求特定的语言。只要该语言可以被编译生成符合标准的class(类)文件,那么就是可以运行在Java虚拟机上了。那么,类文件的结构是什么样的呢? ##三、类文件的基本知识 ##1.基本单位 类文件是以8位字节为基础单位的二进制流,没有任何分割符。当遇到需要占用8位以上的数据时,则会按高位在前的方式分割成若干个8位字节进行存储。 ###2.存储数据的数据格式:无符号数和表。 无符号数属于基本数据类型。以u1,u2,u4,u8来分别代表1个字节,2个字节,4个字节,8个字节的无符号数,无符号数可以用来描述数字、索引引用、数量值或者安装UTF-8编码构成的字符串值。 表是由多个无符号数或者其他表作为数据项构成的复合数据类型,所有表都习惯性以_info结尾。 ##三、类文件的结构 ###1.魔数和版本号 class文件的前四个字节称为魔数(Magic Number),用来描述文件的格式,class文件的魔数是0xCAFEBABE。第五六个字节描述次版本号(Minor Version),第七八个字节描述主版本号。 ###2.常量池 紧接着主版本号之后是常量池的入口。由于常量池的常量数量是变化的,所以在常量池的入口有一个u2类型(第9,10位)的数据,代表常量池容量计数值。不过这个计数是从1开始的,所以如果这个值是22,则代表有21个常量。 常量池中主要有两种类型:字面量(Literal)和符号引用(Symbolic References)。
a.字面量: 接近java语言的常量的概念,如文本字符串,声明为final的常量值等 b.符号引用:1.类和接口的全限定名(Fully Qualified Name) 2.字段的名称和描述符(Descriptor) 3.方法的名称和描述符
java代码在编译时不会像c/c++一样进行“连接”,这样在编译生成的class文件中不会保存各个方法、字段的最终内存布局信息,而是在运行的时候进行动态连接。也就是从常量池中获得方法、字段对应的符号引用,再在类创建或运行时解析翻译到具体的内存地址之中。 常量池中每一个常量都是一个表,在JDK1.7前共有11中常量,在JDK1.7中为了更好的支持动态语言调用,又额外增加了3种(CONSTANT_MethodHandle_info、CONSTANT_MethodType_info和CONSTANT_InvokeDynamic_info)。 这14个表的共同之处在于,表开始的第一项是一个u1类型的标志位(tag),代表当前这个常量属于哪种常量类型。
| 类型 | 标志 | 描述 |
|---|---|---|
| CONSTANT_Utf8_info | 1 | UTF-8编码的字符串 |
| CONSTANT_Integer_info | 3 | 整型字面量 |
| CONSTANT_Float_info | 4 | 浮点型字面量 |
| CONSTANT_Long_info | 5 | 长整型字面量 |
| CONSTANT_Double_info | 6 | 双精度浮点型字面量 |
| CONSTANT_Class_info | 7 | 类或接口的符号引用 |
| CONSTANT_String_info | 8 | 字符串类型字面量 |
| CONSTANT_Fieldref_info | 9 | 字段的符号引用 |
| CONSTANT_Methodref_info | 10 | 类中方法的符号引用 |
| CONSTANT_InterfaceMathodref_info | 11 | 接口中方法的符号引用 |
| CONSTANT_NameAndType_info | 12 | 字段或方法的部分符号引用 |
| CONSTANT_MethodHandle_info | 15 | 表示方法句柄 |
| CONSTANT_MethodType_info | 16 | 表示方法类型 |
| CONSTANT_InvokeDynamic_info | 18 | 表示一个动态方法调用点 |
###3.访问标志 在常量池结束之后,紧接着的是访问标志,用来描述一些类和接口的访问信息,包括这个Class是类还是接口,是否定义为public,是否是abstract如果是类的话,是否是final。 ###4.类索引,父类索引与接口索引集合 访问标志之后是类索引,父类索引与接口索引集合。类索引(this_class)和父类索引(super_class)都是一个u2类型的数据,而接口索引集合(interfaces)是一组u2类型的数据集合(对应java语言中的单继承和多接口实现), ###5.字段表集合 再之后是字段表集合。字段表(Field_info)用于描述接口或者类中声明的变量。字段(field)包括类级变量以及实例级变量,但不包括在方法内部声明的局部变量。一个字段的描述包括:字段的作用域(public,private,protected修饰符)、是实例变量还是类变量(static修饰符)、可变性(final)、并发可见性(volatile修饰符,是否强制从主内存读写)、可否被序列化(transient修饰符)、字段数据类型(基本类型,数组,对象)、字段名称。 ###6.方法表集合 字段表之后是方法表集合。很显然,对方法的描述和对字段的描述是很像的。volatile和transient不能描述方法,但是syncronized、native、strictfp和abstract是方法独有的。
Java虚拟机学习记录(八) —— 虚拟机性能监控与故障处理工具
一、前言
我觉得Java的强大之处在于它有非常完善的生态环境,从开发工具到分析处理工具。使用JDK中提供的工具可以在遇到程序故障时快速定位故障发生的原因并进行调优。
二、JDK命令行工具
a、jps(JVM Process Status):虚拟机进程状况工具
jps可以用来列出正在运行的虚拟机进程,并显示虚拟机执行主类(Main class,main函数所在的类)名称以及这些进程的本地虚拟机唯一ID(Local Virtual Machine Identifier,LVMID)。
jps命令格式: jps [option] [hostid] 使用范例: jiang@jiang-HP-ENVY-Notebook:~$ jps -l 6084 /home/jiang/eclipse//plugins/org.eclipse.equinox.launcher_1.3.200.v20160318-1642.jar 6152 sun.tools.jps.Jps jps可以通过RMI协议查询开启了RMI服务的远程虚拟机进程状态,hostid为RMI注册表中注册的主机名。
| 选项 | 作用 |
|---|---|
| -q | 只输出LVMID,省略主类的名称 |
| -m | 输出虚拟机进程启动时传递给主类main()函数的参数 |
| -l | 输出主类的全名,如果进程执行的是Jar包,输出Jar路径 |
| -v | 输出虚拟机进程启动时JVM参数 |
b、jstat(JVM Statistics Monitoring Tool): 虚拟机统计信息监视工具
jstat是用于监视虚拟机各种运行状态信息的命令行工具。它可以显示本地或者远程虚拟机进程中的类加载、内存、垃圾收集、JIT编译等运行数据。
jstat命令格式为: jstat [option vmid [interval [s|ms] [count]] ] 如果VMID是本地进程,和LVMID是一样的,如果是远程虚拟机进程,那VMID的格式是: [protocol:][//]lvmid[@hostname[:port]/servername] 参数inerval和count代表查询间隔和次数,如果省略则表示只查询一次。 使用范例: jstat -gc 2764 250 20 代表每250ms查询一次进程2764垃圾收集状况,一共查询20次
| 选项 | 作用 |
|---|---|
| -class | 监视类装载,卸载数量,总空间以及类装载所耗费的时间 |
| -gc | 监视Java堆状况,包括Eden区,两个survivor区,老年代,永久代等的容量、已用空间、GC时间合计等信息 |
| -gccapacity | 监视内容与-gc基本相同,但输出主要关注Java堆各个区域使用到的最大、最小空间 |
| -gcutil | 监视内容与-gc基本相同,但输出主要关注已使用空间占总空间的百分比 |
| -gccause | 与-gcutil功能一样,但会额外输出导致上一次GC的原因 |
| -gcnew | 监视新生代GC状况 |
| -gcnewcapacity | 监视新生代使用到的最大、最小空间 |
| -gcold | 监视老年代GC状况 |
| -gcoldcapacity | 监视老年代使用到的最大、最小空间 |
| -gcpermcapacity | 输出永久代使用到的最大、最小空间 |
| -compiler | 输出JIT编译器编译过的方法、耗时等信息 |
| -printcompilation | 输出已被JIT编译的方法 |
Java虚拟机学习记录(七)——内存分配与回收策略
一、前言
Java的内存分配,从全局来看,就是堆上分配(但也可能经过JIT编译后被拆散为标量类型并间接的栈上分配,对象的分配主要在新生代的Eden区上,如果开启了本地线程分配缓冲,将按线程优先在TLAB上分配。少数情况下也可能会直接分配在老年代中(大的对象直接进入老年代)。
二、对象优先在Eden分配
Java堆的新生代中,被分为Eden和两个survivor。大多数情况下,对象在Eden区优先分配,当Eden区没有足够的空间进行分配时,虚拟机将会发起一起Minor GC 新生代GC(Minor GC):指发生在新生代的垃圾回收动作。 老年代GC(Major GC/Full GC):指发生在老年代的GC。
三、大对象直接进入老年代
大对象指的是要占用大量连续内存空间的Java对象,最典型的大对象就是那种很长的字符串以及数组。大对象的内存分配堆虚拟机来说是一件很难的事,因为往往会因为找不到这样的连续的内存空间而不得不提前触发一次Full GC。因此,在写程序中要尽量避免这样大对象,尤其是生命周期很短的大对象。大对象的分配一般会直接进入老年代。(这里可以认为JVM是很不支持生命周期很短的大对象的创建的)。
四、长期存活的对象将进入老年代
虚拟机为每个对象定义了一个年龄计数器,在一次GC后仍然存活的对象它的年龄就会+1,如果对象在Eden出生并且经过第一次Minor GC仍然存活并且Survivor能够容纳就会被移到Survivor(其实就是标记-复制法)。当它的年龄达到一定的程度(默认为15岁),就会被移入老年代。可以通过-XX:MaxTenuringThreshold来设定这个年龄阈值。
五、动态年龄判定
为了更好地适应不同程序的内存情况,虚拟机并不是永远都要求对象的年龄必须达到了MaxTenuringThreshold才能进入老年代,如果在Survivor区中相同年龄所有对象的大小总和大于Survivor空间的一半,年龄大于或等于该年龄的对象就可以直接进入老年代(节省了一半以上的Survivor内存)。
六、空间分配担保
在新生代的Minor GC是采用的标记——复制法,所以一次Minor GC后会将存活的对象移到另一个空闲的Survivor区中,但是没有人可以保证一次GC后存活的对象是Survivor能够容纳的,那么就需要老年代的进行空间分配担保,以防止在容纳不下的情况下有后备的解决方案。所以过程是: Minor GC发生之前:检查老年代的连续空间是否能够容纳下新生代的所有对象,如果可以,则可以确保Minor GC是正常的。如果不可以,虚拟机就会检查HandlePromotionFailure设置值是否允许担保失败。如果允许,那么就会检查老年代最大可用连续空间是否大于历次进入老年代对象的平均大小,如果大于,则尝试一次Minor GC;如果小于,或者不允许担保失败,就要进行一次Full GC(所以可以理解为Full GC是为了给Minor GC腾出空间,所以Full GC之后往往跟随着一次Minor GC)。
Java虚拟机学习记录(六)——HotSpot算法实现
一、前言
在JVM运行的过程中,垃圾回收是性能提升的重中之重,垃圾回收的前提是准确判定哪些对象是可以回收的,在前面的学习中说到,Java的大多数虚拟机都是通过可达性分析算法来判定对象能否回收。那么如何去找这些**根节点(GC ROOTS)**的位置也是一个要解决的问题。
二、HotSpot枚举根节点(GC Roots)
根节点主要在全局性的引用(常量和类的静态属性)和执行上下文中(例如栈帧的本地变量表中),因为这些区域的占用内存往往很大,不可能去逐个检索,因为这个操作太耗时了。 同样的,可达性分析的时间严格要求还体现在GC停顿上,GC停顿就是指在可达性分析期间所有的Java执行线程得全部停下来,等分析完成之后再开始重新运行,如果不停顿,就可能导致分析期间,引用关系还在不断的改变。很显然,这个停顿时间必须短不然用户体验极差。Sun把这个停顿叫做Stop the world。 HotSpot采用一种叫OopMap的数据结构来记录所有的执行上下文和全局引用位置,这样就可以直接得到所有的GC Roots的地址了。 但是在Java程序运行过程中,有很多指令会导致对象的引用关系发生变化,如果每个变化都要写入到OopMap中,那样就需要维护一个很大的OopMap数据结构,会占用大量的空间。所以在Jvm中有一个**安全点(SafePoint)的概念。HotSpot只在安全点处记录了这些信息,然后开始GC。安全点的选定不能太少造成GC等待时间过长,也不能频繁GC增加运行负荷。 如何让所有线程跑到安全点时停止下来,有两种方案可以选择,抢先式中断(Preemptive Suspension)和主动式中断(Voluntary Suspension)。 其中抢先式中断不需要线程的执行代码主动配合,在GC发生时,首先让所有线程中断,如果发现线程中断的地方不在安全点上,就恢复线程,让它跑到安全点上。现在几乎没有虚拟机实现采用抢先式中断来暂停线程从而响应GC事件。 主动式中断的思想是当GC需要中断线程的时候,不直接对线程操作,仅仅简单地设置一个标志,各个线程去主动轮询这个标志,发现中断标志为真时就自己中断挂起。轮询标志的地方和安全点是重合的,另外加上创建对象需要分配内存的地方。 但是安全点只能很好的解决运行中的程序,对于“不运行”的程序也就也就无法进入安全点,也就无法进行GC。这里的不运行指的是线程没有分配到CPU时间,典型的例子就是线程处于Sleep状态或者Blocked状态,这时候线程是无法响应JVM的中断请求的,“走”安全的地方去中断挂起,JVM显然也不太可能等待线程重新被分配CPU时间。这种情况需要借助安全区域(Safe Region)**来解决。 安全区域指的是在一段代码中,引用关系不会发生变化。在这个区域任意开GC都是安全的。我们也可以把安全区域当成是安全点的扩展。 当线程执行到安全区域中时,首先标识自己进入了安全区域。在这段时间内JVM发起GC就不用管安全区域里的线程了。但是在安全区域内的线程重新获得CPU时间要离开Safe Region时,要检查系统是否已经完成了根节点枚举。完成了才能离开否则就要等待完成。 ##三 HotSpot垃圾收集器的实现
a.Serial收集器
这是一款最基本,发展历史最悠久的收集器。这个收集器是一个单线程收集器,并且在收集垃圾时,必须暂停其他所有工作线程。适用于作为Client模式下的虚拟机。
b.ParNew收集器
其实就是Serial收集器的多线程版本。在单CPU的环境中,性能比不上Serial收集器,但是多CPU的时候性能是要好过Serial收集器的。
c.parallel Scavenge收集器
新生代收集器,复制算法,这个收集器与其他收集器的区别在于,Parallel Scavenge收集器的目标是达到一个可控制的吞吐量。吞吐量=运行用户代码所花费的时间/(运行用户代码时间+垃圾收集时间)。而其他收集则是关注减少GC停顿的时间。
d.Serial Old收集器
是Serial收集器的老年代版本,使用标记整理算法。也是给Client模式下的虚拟机使用。在server模式下,还有两大用途:1.在JDK1.5之前和Parallel Scavenge配合使用; 2作为CMS收集器的后备预案,在并发收集发生Concurrent Mode Failure失败时使用。
e.Parallell Old收集器
是Parallel Scavenge收集器的老年代版本,使用多线程和标记-整理算法。配合paraller Scavenge使用。
f.CMS收集器
Concurrent Mark Sweep。以获取最短时间停顿为目标,基于“标记-清除”算法。包括四个步骤: 1.初始标记 2.并发标记 3.重新标记 4.并发清除 他有一下几个缺点: 1.对CPU资源敏感,对性能影响大 2.无法清理浮动垃圾 3.容易产生内存碎片,触发Full GC。
g.G1收集器
是一款面向服务器的垃圾收集器。有以下特点: 1.并行和并发 2.分代收集 3.空间整合 4.可预测的停顿