月度存档: 四月 2015

记一次排查内存泄露

今天一台java帐号服上报了outofmemory,这种错误出现,大多数情况都是有内存泄露导致的。

看程序运行目录下自动生成了 java_pid32123.hprof 文件。这是java自动dump出来的文件,里面记录了内存不足时的内存信息。

可以用jhat打开hprof文件。

耗时会比较长,耐心等待。

上面的7000,是指打开了一个http 7000端口,我们可以通过浏览器进行查看。

通过浏览器打开后,拉到最后面:

点击show instance counts for all classes

看到最上面几行,基本上就可以确认了SocketRunner出现了内存泄露。

生成了大量socketrunner,导致无法及时处理,最终耗尽了所有内存。

svn批量处理

批量添加文件至svn

svn update | awk '{if($1 == "?"){print $2}}' | xargs svn add

svn commit

 

 

批量解决 : Node remains in conflict

svn resolve --accept theirs-full .
svn update | awk '{if($1 == "Skipped"){print $2}}' | xargs svn resolved
svn update
svn resolve --accept theirs-full .

 

批量提交已经删除的文件

svn status | awk '{if($1 == "!"){print $2}}' | xargs svn rm

nginx proxy造成大量wait timeout连接

nginx使用的是1.4.5,发现产生了大量wait timeout,网上搜索得知需要指定为http 1.1及keepalive可大量减少wait-timeout连接。

修改配置添加keepalive字段到upstream。

<span class="line-number">1</span>
<span class="line-number">2</span>
<span class="line-number">3</span>
<span class="line-number">4</span>
<span class="line-number">5</span>
<code class=""><span class="line">upstream backend_abc {
</span><span class="line">    server   192.168.1.34:8086 weight=1 max_fails=2 fail_timeout=10s;
</span><span class="line">    server   192.168.1.77:8086 weight=1 max_fails=2 fail_timeout=10s;
</span><span class="line">    keepalive 16;
</span><span class="line">}</span></code>

同时修改配置添加http1.1声明和header中connection重写。

<span class="line-number">1</span>
<span class="line-number">2</span>
<span class="line-number">3</span>
<span class="line-number">4</span>
<span class="line-number">5</span>
<span class="line-number">6</span>
<span class="line-number">7</span>
<span class="line-number">8</span>
<span class="line-number">9</span>
<span class="line-number">10</span>
<span class="line-number">11</span>
<span class="line-number">12</span>
<code class=""><span class="line">server {
</span><span class="line">        listen       80;
</span><span class="line">        ....
</span><span class="line">  location / {
</span><span class="line">            proxy_pass         http://backend_abc;
</span><span class="line">            proxy_http_version 1.1;
</span><span class="line">            proxy_redirect     off;
</span><span class="line">            proxy_set_header Connection "";
</span><span class="line">            ....
</span><span class="line">  }
</span>
<span class="line">    }</span></code>

android隐藏标题栏与状态栏

requestWindowFeature(Window.FEATURE_NO_TITLE);    // 隐藏标题栏
getWindow().addFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN);  // 隐藏状态栏

上面两行注意要在setContent之前调用。

Required plug-in compatibility UUID not present in DVTPlugInCompatibilityUUIDs

上周五升级了xcode,结果打包时失败,提示错误:

2015-04-11 17:09:54.827 xcodebuild[49636:2989038] [MT] PluginLoading: Required plug-in compatibility UUID 9F75337B-21B4-4ADC-B558-F9CADF7073A7 for plug-in at path ‘~/Library/Application Support/Developer/Shared/Xcode/Plug-ins/Unity4XC.xcplugin’ not present in DVTPlugInCompatibilityUUIDs

今天看了下,应该是因为升级导致插件的uuid对应不上。

以下脚本修复这个问题。

XCODEUUID=`defaults read /Applications/Xcode.app/Contents/Info DVTPlugInCompatibilityUUID`
for f in ~/Library/Application\ Support/Developer/Shared/Xcode/Plug-ins/*; do defaults write "$f/Contents/Info" DVTPlugInCompatibilityUUIDs -array-add $XCODEUUID; done

参考:

http://stackoverflow.com/questions/20732327/xcode-5-required-plug-in-not-present-in-dvtplugincompatibilityuuids

ipa如何确认是否为64位

打出的ipa包,实际是使用的zip格式。
在mac os下可以使用unzip直接进行解压
unzip Unity-iPhone4444.ipa
会在当前目录下生成Payload目录,
进入Payload目录
使用命令lipo来查看,通过ipa中的可执行文件放在     xiyouxiangmopian.app/xiyouxiangmopian
输出 arm64表示已经是64位包
localhost:Payload sanx$ lipo -info xiyouxiangmopian.app/xiyouxiangmopian
Architectures in the fat file: xiyouxiangmopian.app/xiyouxiangmopian are: armv7 arm64
localhost:Payload sanx$

dialog没有全屏

项目中使用了视频,视频上下都是黑边,所以设置backgroundcolor为黑色,但是最上面有一点一直没有被填充上(黄色部分),写测试发现是视频所在的dialog没有全屏。

最早怀疑是最上面的状态栏的问题,看高度正好和状态栏的高度相同。

但无论如何设置backgroundcolordrawable,padding,margin,layoutparam都无法解决问题,而且输出查看也没问题。

只能采取减少法了,不断删除相应的代码并观察,看看删除到哪里才不出现这个问题。

在删除时,突然发现在有段代码有:

		// this.getWindow().setLayout(screenWidth, screenHeight);

		mButton.setVisibility(View.INVISIBLE);
	}

看上面被注释掉那一行,这段代码在设置了视频了dialog后又重新了window的layout,难道问题出在这里?注释掉果然解决掉了问题。

 

java threading

一个老外哥们实现的non-blocking future,可是写法未免太反人类了点。

看来java处理这方面果真是弱项。

http://stackoverflow.com/questions/826212/java-executors-how-to-be-notified-without-blocking-when-a-task-completes

http://fasterjava.blogspot.de/2014/09/writing-non-blocking-executor.html

看要要转向vertx.io / skynet 比较好一些。

ssh连上断开的session

网络不好时,ssh远程连服务器经常断掉,如果原来启动一个带输出的程序,断线重连后,无法继续看下原来的输出。

http://www.gnu.org/software/screen/

screen可以实现断线后继续连上原来的session,当然,ssh后,先启动screen,断线重连后,使用 screen -r即可以继续原来的session.

mysql jdbc failover

因为项目中有多个cobar节点,现在只是连接的单一cobar节点,想修改为连接多个cobar节点,失败后,自动切换至其它节点。

原来看druid时,印象中有druid-ha,高高兴兴拿过来用,发现无法使用,再看源码,发现根本就没实现嘛。

在网上搜索了下,相关的资源也不是非常多。

好在需求很简单可以自已来造个轮子。

代码如下:

package cn.joylab.game.util;

import java.sql.Connection;
import java.util.List;

import javax.sql.DataSource;

import org.apache.commons.lang.math.RandomUtils;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.jdbc.datasource.AbstractDataSource;

public class HADataSource extends AbstractDataSource {

	private List<DataSource> targetDataSources;
	private int index = RandomUtils.nextInt(2);

	public List<DataSource> getTargetDataSources() {
		return targetDataSources;
	}

	public void setTargetDataSources(List<DataSource> targetDataSources) {
		this.targetDataSources = targetDataSources;
	}

	public Connection getConnection() {
		log.info("getConnection()");
		for (int m = 0; m < targetDataSources.size(); m++) {
			try {
				DataSource dataSource = targetDataSources.get(index);
				Connection conn = dataSource.getConnection();
				log.info("getConnenction success from index : " + index);
				return conn;
			} catch (Exception e) {
				index = (++index) % targetDataSources.size();
				log.error("ERROR", e);
			}
		}
		throw new RuntimeException("db connection error");
	}

	public Connection getConnection(String username, String password) {
		log.info("getConnection() with username and password");
		return null;
	}

	private static final Log log = LogFactory.getLog(HADataSource.class);
}

只是简单的进行下datasource的切换。