对,正义象怕鬼的小姑娘——非得同伴足够多她才敢露面。
游客 | 使用Gmail登录

GAE Java的无限重定向问题

Java版的Google app engine存在一个bug,会导致在请求返回404状态时陷入无线的重定向中。这个bug只存在于生产环境,在gae测试环境则不会出现,至今尚未修复。

例如,访问一个不存在的地址,http://www.dongliu.net/not_exits.xxx

经经过无数的重定向,变为http://www.dongliu.net/not_exits.xxx/index.jsp/index.jsp/index.jsp/index.jsp/index.jsp/index.jsp/index.jsp/index.jsp/index.jsp/index.jsp/index.jsp/index.jsp/index.jsp/index.jsp/index.jsp/index.jsp/index.jsp/index.jsp/index.jsp/index.jsp/

bug的触发的充分、必要条件:web.xml中包含<jsp-config>标签。我项目中的web.xml就是有了这么一段:

    <jsp-config>
        <jsp-property-group>
        <url-pattern>*.jsp</url-pattern>
        <trim-directive-whitespaces>true</trim-directive-whitespaces>
        </jsp-property-group>
    </jsp-config>

为避免这个问题,只能移除所有的<jsp-config>标签。这是个奇特而且悲剧的bug,<jsp-config>不是必不可少的功能,但是某些情况下还是挺实用的。

Redis rdb dump的问题

rdb是redis支持的一种持久化方式,在进行rdb dump时,redis直接将内存中的所有数据写到磁盘的文件上,以实现持久化。以下三种情况会使用rdb dump:

  1. 通过save/bgsave命令保存数据
  2. 满足配置文件中的save指令条件触发持久化操作
  3. Slave初始连接上Master时,Master会dump一份数据,传输给从库。

rdb有个隐蔽的问题需要注意,就是Redis的工作路径和配置的rdb dump文件的路径必须在同一个硬盘分区上。如果处在不同的分区,所有这些需要使用rdb dump的操作都会失败。

这个问题的产生是由于redis处理dump文件的方式。redis会先把内存中的数据dump到临时文件,在dump完成之后,再从临时文件建立一个硬链接到指定的rdb文件保存位置。redis使用这样的操作以避免出现未完成的dump文件的情况,此部分代码如下:

if (rename(tmpfile,filename) == -1) { 
    redisLog(REDIS_WARNING,"Error moving temp DB file on the final destination: %s", strerror(errno)); 
    unlink(tmpfile); 
    return REDIS_ERR;
}

临时文件使用的是redis的工作路径,如果没有修改redis配置文件中的dir配置项,这个工作路径也就是启动redis所在的路径。如果工作路径和rdb文件保存路径不在同一个分区上,那么rdb dump操作就会在建立硬链接的时候失败。

数组越界检查的优化和消除

数据越界检查(Array Bounds Check),是现在众多主流语言具备的防止数据访问越界的机制,因为这个机制,java/C#/Python/javascript等避免了C/C++中普遍存在的访问越界、缓冲区溢出等头疼问题。

当然数据越界检查会带来额外的开销,在现代语言(如Java,c#)中,一些措施被采用以优化数组越界检查或者在某些情况下可以消除数组越界检查。

数组越界检查的优化

数据越界检查逻辑上是需要两次比较操作的,需要检查下标大于0,并且小于数组的可访问长度,即idx>0 && idx

数组越界检查的消除(Array Bounds Check Elimination)

.net CLR和Java Jvm的Jit会对一些不必要的越界检查进行消除,不同的Jit所具有的越界检查消除能力也不一样,Jit是在运行中进行的,所以必须平衡越界检查消除的开销和收益。举例集中可以做越界检查是消除的情况:

for (int i = 0; i < array.length; i++){
    array[i] = i;
}

这种情况可以完全消除。

for (int i = 0; i < n; i++){
    array[i] = i;
}

这种可以优化为进行一次数组越界检查。

k = a[i];
if (b) {
    k = k + a[i];
} else {
     k = k - a[i];
}

这种可以消除后面两次访问所需的越界检查。

附两个参考:

Array Bounds Check Elimination in the CLR

Array Bounds Check Elimination for the Java HotSpot™ Client Compiler

论移动平台web难以取代客户端

移动应用开发一直流传着一个说法,就是,智能手机和平板会像PC一样,出现web应用代替本地客户端的趋势。鼓吹此观点的人群包括试图扩展自己工作机会、提升工作地位的前端工程师、只听说html5但不知道html5为何物能干什么的产品经理,以及对html5技术狂热的追捧者等等。

这个观点里面原本就蕴含着一个伪命题,即“PC上web应用已经取代本地客户端的位置”。抛开此伪命题不论,移动终端上的本地客户端确实比PC上更多更泛滥,web应用的地位也更低下,这种状况的出现,窃以为有以下因素,并且可预见的时间内,这些情况也不会有什么改观:

1. web应用难以充分利用系统的API和特性。

html5无法访问系统众多接口,如摄像头、读取联系人、GPS访问等,而这些接口对于移动终端应用是至关重要的。html5也无法利用系统的原生GUI组件。PhoneGap等中间层的出现对此有一定的缓解作用,使用其结合html5来开发本地客户端也是现在比较流行的方案。

2.html5面临的用户体验和性能限制。

html5难以实现个性化的UI、操作方式、以及绚丽的特效;移动终端因为计算能力和电池电量的限制,对于应用程序效率的要求更高。

3.移动客户端的开发陈本和发布/更新成本低。

这是最重要的一点,移动客户端的开发成本比PC客户端低得多,html5号称的开发效率优势是很值得怀疑的,可能其对开发效率的唯一重要的提升的就是在与跨移动终端平台方面了。而且困扰桌面客户端的发布和更新问题,也因为有应用市场的存在而变得容易。

Lua现在挺火

最近发布的redis2.6一个重要的特性是引入了服务器端lua脚本支持,这个功能的引入使得可以把一部分计算工作放在redis server上完成,客户端直接获取计算的结果。

Lua起初是作为游戏客户端的扩展编写语言而大红大紫的,其后在国内的一些输入法,浏览器客户端上应用,小巧灵活的Lua表现出色。
如今, Lua在处理高吞吐量请求方面的优势也显现出来,集成在nginx、redis等c程序中用于处理个性化的逻辑,这都得益于Lua对coroutine的支持和本身的高性能。
Lua特点:
  • 与C/C++的良好结合
  • 简单小巧:支持核心的功能而将其他部分交给C扩展实现。只有17000代码,LuaJIT额外有6000行,解释器和链接库加起来只有200k.
  • 可移植性:仅使用ANSI C编写,有 ANSI C的地方就有lua(但是LuaJIT平台相关,目前只支持x86)
  • 语言特性:动态类型,First-class function,closure,generator,coroutine支持
  • 高效:得益于 LuaJIT,Lua号称是最快的脚本语言(之一)。

由于Lua本身的特性和简单性,使得JIT容易实现。引用一段话:"这是一个奇迹,比较Java,Python, JavaScript在相应项目上的投资和收效,这个一个人的项目验证了一个道理,这世界本来很简单,只是我们做复杂了。"

木婉清发布新版

木婉清是个水木社区的客户端,去年春节时写的,之后就放着没动了。

今天春节又翻出来改吧改吧,看起来比之前好了那么一点。实现上界面改用html来写了, 规避了Android原生界面实现上的不少问题,但也出现了同样多的新问题……

未完成的功能和BUG都还有很多,等到下个春节来修复吧。

项目地址:http://code.google.com/p/muwanqing/

下载:http://muwanqing.googlecode.com/files/muwanqing.apk

JVM的DirectMemory设置

几台服务器的JVM占用内存总是持续增长,大大超过-Xmx设定的值,服务器物理内存几乎被耗尽。

使用jmap查看JVM的内存使用,发现jvm的堆大小完全在-Xmx参数设定的范围之内,那问题只能处在别的地方了。

JVM除了堆内存之外,就只有栈内存和DirectMemory了。栈空间每个线程是固定的,线程数也没可能多到可以占用这么多内存的程序,所以怀疑的目标就在DirectMemory上了。

DirectMemory是java nio引入的,直接以native的方式分配内存,不受jvm管理。这种方式是为了提高网络和文件IO的效率,避免多余的内存拷贝而出现的。DirectMemory占用的大小没有直接的工具或者API可以查看,不过这个在Bits类中是有两个字段存储了最大大小和已分配大小的,使用反射可以拿到这个数据:

Class<?> c = Class.forName("java.nio.Bits");
Field maxMemory = c.getDeclaredField("maxMemory");
maxMemory.setAccessible(true);
Field reservedMemory = c.getDeclaredField("reservedMemory");
reservedMemory.setAccessible(true);
Long maxMemoryValue = (Long)maxMemory.get(null);
Long reservedMemoryValue = (Long)reservedMemory.get(null);

结果证实了猜测,DirectMemory增长失控了。

原来,DirectMemory 的默认大小是64M,而JDK6之前和JDK6的某些版本的SUN JVM,存在一个BUG,在用-Xmx设定堆空间大小的时候,也设置了DirectMemory的大小。加入设置了-Xmx2048m,那么jvm最终可分配的内存大小为4G多一些,是预期的两倍。

解决方式是设置jvm参数-XX:MaxDirectMemorySize=128m,指定DirectMemory的大小。

为Process.waitFor设置超时

Java中在使用Runtime.getRuntime().exec(command)调用系统命令后,一般会调用Process.waitFor()来等待命令执行结束,获取执行结果。今天一个悲剧的事实证明了,即使只是调用了很简单的脚本命令,在调用Process.waitFor()后同样可能发生无休止或者接近于无休止的阻塞。处理完故障之后痛定思痛,决定在代码中加入超时控制,但是Process.waitFor()本身并不支持超时时间设置。一个方法是改用非阻塞的Process.exitValue()方法,然后轮询检查进程状态,这种方式比较消耗CPU,以至于轮询间隔也不能设置得太小,总归不是很完美。另外就是多起一个线程,借助于其他的超时机制来控制。最后使用的代码如下:

public class ProcessUtils {
   
    /**
     * 运行一个外部命令,返回状态.若超过指定的超时时间,抛出TimeoutException
     * @param command
     * @param timeout
     * @return
     * @throws IOException
     * @throws InterruptedException
     * @throws TimeoutException
     */
    public static int executeCommand(final String command, final long timeout) throws IOException, InterruptedException, TimeoutException {
        Process process = Runtime.getRuntime().exec(command);
        Worker worker = new Worker(process);
        worker.start();
        try {
            worker.join(timeout);
            if (worker.exit != null){
                return worker.exit;
            } else{
                throw new TimeoutException();
            }
        } catch (InterruptedException ex) {
            worker.interrupt();
            Thread.currentThread().interrupt();
            throw ex;
        } finally {
            process.destroy();
        }
    }
   

    private static class Worker extends Thread {
        private final Process process;
        private Integer exit;

        private Worker(Process process) {
            this.process = process;
        }

        public void run() {
            try {
                exit = process.waitFor();
            } catch (InterruptedException ignore) {
                return;
            }
        }
    }

}

SAE还是太寨了

这两天研究和试用的感觉,这东西不靠谱,BUG很多,容错和扩展能力都很可疑。

看到这样的问题回复,实在让人无法放心吧:

一淘的死法

从之前爱帮败诉于大众点评,就可以预见到一淘的后果了。

一淘想要做入口,必须得电商数量众多,实力平均才有可能;像京东之类,实力远超其他电商,本身已成为购物首选站点,又怎么会容忍一淘抢夺用户流量。

一淘的悲剧之处就在于,他所损害的,正是他所最依赖的,离开了京东、易购、当当的一淘一文不值。他比爱帮还悲剧的地方在于,爱帮是中立的第三方,而淘宝却同时身兼裁判员和运动员的角色。

共325篇,第1/33页 首页 1 2 3 4 5 6 7 8 9 10 11 ... 下一页 尾页