JVM内存溢出相关问题

问题

平时我们遇到最多的内存溢出的问题,我这里大略总结为以下三种

  • OutOfMemoryError: Java heap space
  • OutOfMemoryError: PermGen space
  • OutOfMemoryError: unable to create new native thread

解决方案

根据实际情况,首先应排查应用项目本身的问题,除此之外,
Java heap space的问题我们可以通过增大heap内存(即堆内存)来解决,比如

1
-Xms:1024m -Xmx:1024m

其中Xms指初始堆大小,默认为物理机内存的1/64,Xmx指最大堆大小,默认为物理机内存的1/4。注意:堆内存受限于操作系统。详细

PermGen space 可以通过减少或者共享第三方jar库来解决,或者调整以下参数

1
-XX:PermSize=64M -XX:MaxPermSize=128m

至于最后一种无法创建本地线程的问题,需要根据实际情况进行计算:
具体计算公式如下:

1
(MaxProcessMemory - JVMMemory - ReservedOsMemory) / (ThreadStackSize) = Number of threads

  • MaxProcessMemory 指的是一个进程的最大内存
  • JVMMemory JVM内存
  • ReservedOsMemory 保留的操作系统内存
  • ThreadStackSize 线程栈的大小

比如,32位的windows的MaxProcessMemory为2G,eclipse默认启动JVMMemory为64M,ReservedOsMemory一般为130M左右,JDK 1.6默认的ThreadStackSize为325k,所以代入公式为(210241024-64*1024)/325=5841。
所以理论上分配给JVM的内存越大就会制约它所能创建的线程数。

小结

解决内存溢出的问题当然不能依赖于调增JVM内存,更重要的是对项目进行质量上的监管和优化,然后配合JVM进行优化。

开始Markdown写作

简介

Markdown是一种简易的标记语言,目前依然成为众多程序员和其他写作爱好者的首选,它是一种能让作者专心于写作内容的轻量级语言。更多

语法

标题

1
2
3
4
5
6
7
# 代表一级标题
## 代表二级标题
### 代表三级标题
以此类推,共6级标题
当然,我们也可以用另一种方式来标记一级和二级标题
============= 可表示一级标题
------------- 表示二级标题

列表

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
无序列表

在列表前加入'+'、'-'或者'*',后面跟 空格,如下:
- 列表1
- 列表2
- 列表3
或者
* 列表1
* 列表2
* 列表3

有序列表

在列表前加 序号,后面跟 空格,如下:
1. 列表1
2. 列表2
3. 列表3

图像

有时候我们需要为文档引入图片,可使用如下语法:

1
2
3
4
5
![Alt text](/path/to/img.jpg)
![Alt text](/path/to/img.jpg "Optional title")
以上参数依次为:
Alt text 代表图片的替代文字
Optional title代表 可选的 'title' 文字。

链接

链接的语法跟图片相似,如下:

1
[链接文字](链接URL)

引用

引用的文字可以通过’>’来标记

段落

段落可以通过 一个制表符 或 四个空格 来生成。

分割线

如果想要在一行生成分割线,我们可以通过三个以上’*’,”-“或者”_”来生成,中间可以加空格,所在行不能有其他文字,如下:

1
2
3
4
* * *
- - -
---
_____

参考

Markdown语法
维基百科-Markdown

关于升级maven构建webapp版本的问题

问题

工作中如果我们通过maven来管理项目,由于maven的一些插件更新比较慢,比如本文所述maven-archetype-webapp,目前版本为1.0或1.1,如果我们构建器插件来新建一个webapp项目的时候,那么默认配置将会是基于jdk1.5和web2.3的项目,so 问题来了!我们要怎样将此项目变更为基于jdk1.7或web 3.0的项目呢?

解决方案

当然你可以使用新建动态项目之流的方式,当本文所述依然为maven插件形式。

  • 你可以升级上述maven-archetype-webapp插件,发布到工作组的私服中。
  • 切换至项目所在目录,编辑.setting目录下的org.eclipse.wst.common.project.facet.core.xml文件,如下:
1
2
3
4
5
6
7
<?xml version="1.0" encoding="UTF-8"?>
<faceted-project>
<fixed facet="wst.jsdt.web"/>
<installed facet="jst.web" version="3.0"/><!-- 此处配置web.xml的版本-->
<installed facet="wst.jsdt.web" version="1.0"/>
<installed facet="java" version="1.8"/><!-- 此处配置jdk的版本-->
</faceted-project>

当然别忘记更新项目中web.xml中的描述文件,如下可选:

web.xml 2.5

1
2
3
4
5
6
7
<?xml version="1.0" encoding="UTF-8"?>  
<web-app xmlns="http://java.sun.com/xml/ns/javaee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd"
version="2.5">

</web-app>

web.xml 3.0

1
2
3
4
5
6
7
8
<?xml version="1.0" encoding="UTF-8"?>      
<web-app
version="3.0"
xmlns="http://java.sun.com/xml/ns/javaee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd">

</web-app>

  • 配合maven-plugin-compile插件,设置编译版本为jdk1.7,如下:
1
2
3
4
5
6
7
8
9
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<configuration>
<!-- or whatever version you use -->
<source>${java.version}</source>
<target>${java.version}</target>
</configuration>
</plugin>

关于'The submodule *** was not properly initialized with a .gitmodules file'

问题描述

1
$ Your page is having problems building: The submodule themes/next was not properly initialized with a .gitmodules file. For more information, see https://help.github.com/articles/page-build-failed-missing-submodule.

分析

此问题一般是因为git仓库中引用其他git仓库,而未通过子模块添加或初始化原因导致的。

解决方案

在已经通过git版本控制的代码库里,如果需要引入另外一个git管理的项目时,我们可以通过 git submodule命令来添加

1
$ git submodule add https://github.com/xxx.git /path/xxx

参考

使用WebHarvest攫取页面数据

简介

WebHarvest是一款Java实现的页面数据提取工具,可以通过xpath,xquery等xml技术,精准高效灵活的对所关心的数据进行提取。

快速起步

接下来,我们将通过获取一个网站页面来进行。

入口

首先我们应该先实例化一个“小爬虫”,如下

1
2
3
4
String configFile = "xxx";//此处是爬虫爬取数据的规则文件,需用户编写。如:"scraper-taobao.xml",可使用相对路径或绝对路径。
String scraperPath = "xxx";//此处配置爬取的根目录,如需生成本地数据文件,请指定系统绝对路径。如:D:/scraper,请注意路径分隔符。
ScraperConfiguration config = new ScraperConfiguration(configFile);
Scraper scraper = new Scraper(config, scraperPath);

配置

1
2
scraper.addVariableToContext("param1", "value1");
scraper.addVariableToContext("param2", "value2");

如上,可将参数param1和param2传入scraper会话当中,从而在规则文件中动态获取参数。

启动

1
scraper.execute();

爬虫爬取过程将会阻塞线程,所以性能不是很好。

处理数据

1
Variable articles = (Variable) scraper.getContext().get("articles");

爬虫完毕后,会将爬到的数据保存到会话上下文中,我们可以通过获取规则文件中指定的参数,并转换为后台程序需要的数据,默认支持List,String,Integer等类型。

编写规则文件

WebHarvest的规则文件是其核心,也是我们青睐它的原因之一,但目前编写该规则文件对程序员的门槛依然相对较高,虽然作者提供了IDE来简化编写难度,如下:
WebHarvest IDE

诚然,熟悉了语法之后,我们就可以通过徒手编写规则来完成了,以下是需要了解的关键技术:

  • xpath 一门可以在XML文档快速定位和查找结点的语言。
  • regex 业界通用的强大到无敌的正则表达式。
  • xquery 可以将XML作为SQL容器的语言。

更对用法请参考官方文档

关于Spring整合Quartz的问题

问题描述

Caused by: Java.lang.IncompatibleClassChangeError: class org.springframework.scheduling.quartz.CronTriggerBean has interface org.quartz.CronTrigger as super class

解决方法

如上问题,一般是由于spring 3.x 和 quartz 2.X版本不兼容导致,具体原因是org.quartz.CronTrigger在2.0以后从class变成了一个接口导致,坑啊,所以说前期设计架构一定要搞好啊。
trigger 用 org.springframework.scheduling.quartz.CronTriggerFactoryBean

1
2
3
4
5
6
7
<!-- 基于Cron表达式的打火器 -->
<bean id="cronTrigger"
class="org.springframework.scheduling.quartz.CronTriggerFactoryBean">

<property name="jobDetail" ref="jobDetail" />
<!-- 每分钟执行一次 -->
<property name="cronExpression" value="*/30 * * * * ?" />
</bean>

上述问题还有可能存在于Tomcat版本不兼容的问题上,比如tomcat-7.0.16中发现会有上述的问题。

问题描述

Caused by: java.io.IOException: JobDataMap values must be Strings when the ‘useProperties’ property is set. Key of offending value: methodInvoker

解决方法

如下:

1
2


问题描述

不能通过依赖注入的方式直接获取bean实例

解决方法

  1. 在Job中通过预先注入好的实例,ApplicationContext.getBean(“xxx”)获取。
  2. 重写 JobBeanFactory,通过配置SchedulerFactoryBean来指定自定义的FactoryBean,如下:
1
2
3
4
5
6
7
8
<bean class="org.springframework.scheduling.quartz.SchedulerFactoryBean">

...此处省略

<property name="jobFactory">
<bean class="com.xxx.AutowiredSpringBeanJobFactory" />
</property>
</bean>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
import org.quartz.spi.TriggerFiredBundle;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.config.AutowireCapableBeanFactory;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.scheduling.quartz.SpringBeanJobFactory;

public class AutowiredSpringBeanJobFactory extends SpringBeanJobFactory implements ApplicationContextAware{

private AutowireCapableBeanFactory factory;

@Override
public void setApplicationContext(ApplicationContext context) throws BeansException {
factory = context.getAutowireCapableBeanFactory();
}

@Override
protected Object createJobInstance(TriggerFiredBundle bundle) throws Exception {
final Object instance = super.createJobInstance(bundle);
factory.autowireBean(instance);
return instance;
}

}

Mysql数据库笔记

概述

安装

1
2
3
4
5
ubuntu
$ sudo apt-get update && sudo apt-get install mysql-server-5.6

centos
$ sudo yum install mariadb-server

配置

1
2
$ /etc/mysql/my.ini
为了能进行远程登录,注释掉bing-address=127.0.0.1一行

操作

  • 登录
1
$ mysql -u root -h localhost -p
  • 建库
1
$ create database db_name default character set utf8;
  • 授权
1
2
3
4
$ grant all privileges on db_name.* to user@'%' identified by 'password';
上述命令授权的同时新建了用户,如要授权已有用户,则不需要指定 identified by 'password'
其中%代表所有IP,即可以进行远程登陆。
$ flush privilges;
  • 建表
1
2
3
4
5
6
$ create table t_tablename (
ID BIGINT NOT NULL,
NAME VARCHAR(200) NOT NULL,
DESCRIPTION VARCHAR(250) NULL,
DATA BLOB NULL,
PRIMARY KEY (ID));
  • 删除表
1
$ drop table if exists t_tablename;
  • 删除数据库
1
$ drop database if exists db_name;
  • 导入脚本
1
2
3
4
5
$ mysql -u user -h localhost -p password -D db_name < /path/script.sql
或者
mysql> source /path/script.sql
或者
mysql> \. /path/script.sql

使用Eclipse对应用进行远端调试

简介

JPDA(Java Platform Debugger Architecture)是 Java 平台调试体系结构的缩写,通过 JPDA 提供的 API,开发人员可以方便灵活的搭建 Java 调试应用程序。 JPDA 主要由三个部分组成:Java 虚拟机工具接口(JVMTI),Java 调试线协议(JDWP),以及 Java 调试接口(JDI)– 引至:IBM DeveloperWorks

实践

开启远程调试端口

1
-Xdebug -Xrunjdwp:transport=dt_socket, address=8000,server=y,suspend=y

  • -Xdebug 启用调试特性
  • -Xrunjdwp 启用JDWP实现,它包含若干子选项:
    transport=dt_socket JPDA front-end和back-end之间的传输方法。dt_socket表示使用套接字传输。
    address=8000 JVM在8000端口上监听请求。
    server=y y表示启动的JVM是被调试者。如果为n,则表示启动的JVM是调试器。
    suspend=y y表示启动的JVM会暂停等待,直到调试器连接上。

suspend=y这个选项很重要。如果你想从Tomcat启动的一开始就进行调试,那么就必须设置suspend=y。

本地maven调试
将以上参数添加至maven启动参数,或者配置到MAVEN_OPTS环境变量中

服务器tomcat调试
将以上参数添加至tomcat启动参数中

配置Eclipse调试器
打开eclipse -> run -> run config,如图:

参考

维基百科
IBM DeveloperWorks

深入学习JAVA虚拟机-垃圾回收算法

概述

JAVA提供了自动垃圾回收管理机制来管理对象的生命周期,本文将对几种常见的算法进行简要介绍。

分类

  • Mark-Sweep 标记-清除
  • Copying 复制
  • Mark-Compac 标记-整理
  • Generational Collection 分代收集

标记-清除 算法是最基础的一种算法,通常通过“标记”和“清除”两个阶段,将需要进行回收的对象进行“标记”,标记完成后统一进行回收处理。这个算法主要存在两个不足:

  1. 效率问题,标记和清除连个过程效率都不高。
  2. 空间问题,通常进行标记和清除后会产生大量不连续的内存碎片,导致后期进行大对象分配时无法找到可用空间而触发不必要的GC动作。

复制 算法提高了 标记-清除算法的效率问题,主要通过将可用内存按容量分成大小相同的两块,每次选用其中一块进行对象内存分配,当内存用完的时候,就将存活的对象复制至另一块,然后将本块区域完全清理。这样使得每次只适用半块内存,所以显而易见的导致了容量浪费,成本变高。
另外,复制算法在对象存活率较高的情况下,由于每次复制很多对象,所以也会直接导致效率的就降低。

标记-整理 算法过程与 标记-清除类似,主要是通过标记对象后,将存活的对象想一端移动,然后对另一端内存进行清理,解决了“内存碎片”问题。

分代收集 算法作为目前商业虚拟机的主流算法,主要根据对象存活周期的不同将内存进行分块管理,一般是将Java堆分为新生代和老年代,根据IBM公司对JVM的专项研究表明,新生代中的对象98%是瞬息而亡的,所以HotSpot虚拟机磨人Eden和Survivor的大小比例是8:1,所以分代收集可以在新生代内存区域选用复制算法,而在老年代内存区域选择标记-清除或者标记整理进行回收。

#小结#
本文主要介绍JVM常用垃圾回收算法,通过了解各种算法来达到对实际生产所遇到的JVM相关问题进行追踪-定位-解决,并且在开发编码过程中尽量迎合虚拟机特性,来提升运行效能。

使用Eclipse IDE

快捷键

比较重要的快捷键

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
代码助手:Ctrl+Space(简体中文操作系统是Alt+/)
快速修正:Ctrl+1
单词补全:Alt+/
打开外部Java文档:Shift+F2

显示搜索对话框:Ctrl+H
快速Outline:Ctrl+O
打开资源:Ctrl+Shift+R
打开类型:Ctrl+Shift+T
显示重构菜单:Alt+Shift+T

上一个/下一个光标的位置:Alt+Left/Right
上一个/下一个成员(成员对象或成员函数):Ctrl+Shift+Up/Down
选中闭合元素:Alt+Shift+Up/Down/Left/Right
删除行:Ctrl+D
在当前行上插入一行:Ctrl+Shift+Enter
在当前行下插入一行: Shift+Enter
上下移动选中的行:Alt+Up/Down


组织导入:Ctrl+Shift+O

### 定位 ###
```code
2.1行内定位
行末/行首:End/Home
前一个/后一个单词:Ctrl+Right/Left
2.2文件内定位
跳到某行:Ctrl+L
上下滚屏:Ctrl+Up/Down
上一个/下一个成员(成员对象或成员函数):Ctrl+Shift+Up/Down
快速Outline:Ctrl+O
2.3跨文件定位
打开声明:F3
打开资源:Ctrl+Shift+R
打开类型:Ctrl+Shift+T
在workspace中搜索选中元素的声明:Ctrl+G
在workspace中搜索选中的文本:Ctrl+Alt+G
在workspace中搜索选中元素的引用:Ctrl+Shift+G
打开调用层次结构:Ctrl+Alt+H
快速层次结构:Ctrl+T
反悔:Ctrl+Z
2.4其它
上一个/下一个光标所在位置:Alt+Left/Right
上一个编辑的位置:Ctrl+Q

选中快捷键

1
2
3
4
5
6
7
3.1行内选中 
选中到行末/行首:Shift+End/Home
选中上一个/下一个单词:Ctrl+Shift+Left/Right
3.2文件内选中
选中闭合元素:Alt+Shift+Up
恢复到上一个选中:Alt+Shift+Down
选中下一个/上一个元素:Alt+Shift+Right/Left

定位/选中/操作同时

1
2
3
4
5
6
7
删除行:Ctrl+D
删除下一个/上一个单词:Ctrl+Delete/Backspace
删除到行末:Ctrl+Shift+Delete
在当前行上插入一行:Ctrl+Shift+Enter
在当前行下插入一行: Shift+Enter
上下移动选中的行:Alt+Up/Down
拷贝选中的行:Ctrl+Alt+Up/Down

代码编辑

1
2
3
4
5
6
7
保存:Ctrl+S
保存所有:Ctrl+Shift+S
下一个命中的项(搜索之后):Ctrl+.
注释:Ctrl+/
添加导入:Ctrl+Shift+M
显示快捷键帮助:Ctrl+Shift+L
变为大/小写:Ctrl+Shift+X/Y

代码重构

1
2
3
4
显示重构菜单:Alt+Shift+T
重构-改变方法签名:Alt+Shift+C
重构-移动:Alt+Shift+V
重构-重命名:Alt+Shift+R

编辑器、视图、透视图切换

1
2
3
4
5
下一个编辑器:Ctrl+F6
下一个视图:Ctrl+F7
下一个透视图:Ctrl+F8
最大化当前视图或编辑器:Ctrl+M
激活编辑器:F12

调试

1
2
3
4
5
F5:Step Into(debug)
F6:Step over(debug)
F7:Step return(debug)
F8:Resume(debug)
F11:debug上一个应用(debug)

方向键

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
Ctrl
前一个/后一个单词:Ctrl+Right/Left
上下滚屏:Ctrl+Up/Down
Alt
上一个/下一个光标的位置:Alt+Left/Right
上下移动选中的行:Alt+Up/Down
Shift
选中上一个/下一个字符:Shift+Left/Right
选中上一行/下一行(从当前光标位置开始):Shift+Up/Down
Ctrl+Shift
上一个/下一个成员(成员对象或成员函数):Ctrl+Shift+Up/Down
选中上一个/下一个单词:Ctrl+Shift+Left/Right
Alt+Shift
选中闭合元素:Alt+Shift+Up
恢复到上一个选中:Alt+Shift+Down
选中下一个/上一个元素:Alt+Shift+Right/Left
拷贝选中的行:Ctrl+Alt+Up/Down
Ctrl+Alt
拷贝选中的行:Ctrl+Alt+Up/Down

F类快捷键

1
2
3
4
5
6
7
8
9
10
F2:显示提示/重命名
F3:打开选中元素的声明
F4:打开选中元素的类型继承结构
F5:刷新
F5:Step Into(debug)
F6:Step over(debug)
F7:Step return(debug)
F8:Resume(debug)
F11:debug上一个应用(debug)
F12:激活编辑器

插件

安装方式

常用的安装方式有三种

  • link文件安装,需离线,推荐。
  • 将插件目录中features和plugins目录中文件分别拷贝至eclipse安装目录中同名目录中,需离线,不推荐。
  • 通过Eclipse Marketplace进行在线安装,需联网,推荐。

普通插件插件推荐link方式
在eclipse安装目录新建links目录,编写xxx.link,内容如下:

1
2
3
4
path=[插件绝对路径],如C:/dev/eclipse-plugins/svn-1.8.22
或者
path=[相对路径],如: ../eclipse-plugins/svn-1.8.22
注:相对路径为eclipse执行文件目录

theme color

Update Site:

1
http://eclipse-color-theme.github.com/update

效果图
colorthemes

subclipse

SVN代码管理的集成插件,下载地址:

propedit

Java Properties文件编辑插件
Update Site:

1
http://propedit.sourceforge.jp/eclipse/updates/

checkstyle

checkstyle
官网:http://checkstyle.sourceforge.net/

emmet

emmet
官网:http://emmet.io/

Emmet is a plugin for many popular text editors which greatly improves HTML & CSS workflow

Updte Site:

1
http://emmet.io/eclipse/updates/

注意:以上插件均可通过Eclipse Marketplace安装

问题

  • eclipse 4.4以后不支持maven2 版本,所以想要打包只能在系统命令行也执行。
,