• OpenSuse 11.3 的安装问题

    帮朋友安装最新的OpenSuse 11.3

    结果到最后安装界面的时候提示:

    The bootloader is installed on a partition that doesn not lie entirely below 128GB. The system might not boot.

    查了一下,原来是要求boot所在分区要在距磁盘MBR(0柱面,0磁道,1扇区)128G以内才行。

    解决方法:
    1.在C盘切割出100M-200M左右的小分区(前提是你的C盘不能大于128G),挂载到linux的/boot文件夹。

    2.让linux分区尽可能靠近C盘(前提还是你的C盘不能大于128G)。我就让他将Windows的D分区删除了给llinux。

    3.如果C盘就大于128G,那就只能重新分区了。

    估计是grub的寻址范围的问题。没有深究。

  • WebRebuild-重构人生 北京站年会 总结

    今天去参加了一下WebRebuild-重构人生 北京站 年会。

    @webrebuild

    Read more...
  • 如何整理和分享A片?

            我有一堆A片(用堆这个量词似乎不合适,但找不到更合适的能表现数量足够多但又不透露太多细节的量词了),太多了,不好找,我要归类一下。于是我建立了一个树形目录,先按照地域归类,欧美,日韩,华语,其他啥的。然后下面按照主演归类,xxx、xxx、xxxx….啥的。然后发现一个问题,光这样归类还不行,比方还需要个标志,说明是有码的还是无码的。于是我在文件名前面加上了这个标志。后来又发现,还有许多信息需要标明,比方是否有暴力呀,是单人还是多人呀,有剧情还是无剧情呀….似乎还需要个评分功能,标志下好看不好看,以及重要性,最好再能附加上
    一段观后感… 于是难住我了。

    Read more...
  • 反模式之流失监听者泄露(Lapsed Listener Leak)

    有这样一段代码:

    public class LapsedListenerTest {
    
        public static class A{
            private List listeners = new CopyOnWriteArrayList();
            private String name;
            public A(String name) {
                this.name = name;
            }
            public void addListener(PropertyChangeListener listener) {
                listeners.add(listener);
            }
            private void fire(String property,Object oldValue,Object newValue) {
                for(PropertyChangeListener listener:listeners) {
                        listener.propertyChange(new PropertyChangeEvent(this, property, oldValue, newValue));
                }
            }
            public void setName(String name) {
                String oldName = this.name;
                this.name = name;
                fire("name", oldName, name);
            }
        }
    
        public static class B implements PropertyChangeListener{
            private int id;
            private A a;
            //占用内存
            private byte[] bt= new byte[1024*1024];
            public B(A a,int id) {
                this.id = id;
                this.a = a;
                this.a.addListener(this);
            }
            @Override
            public void propertyChange(PropertyChangeEvent evt) {
                System.out.println("on B-" B.this.id "(" evt.getPropertyName() "," evt.getOldValue() "," evt.getNewValue() ")");
            }
        }
    
        /**
         * @param args
         * @throws InterruptedException
         */
         public static void main(String[] args) throws InterruptedException {
            A a = new A("A");
            int j = 0;
            while(true) {
                B b = new B(a,j);
                //do some thing with b
                a.setName("A" j);
                b.dispose();
                j  ;
                System.gc();
                Thread.sleep(20);
            }
        }
    
    } 
    

     

    代码片段1

    A类的对象生命周期都比较长,而B类的对象生命周期都比较短,它需要监听A类的属性变化而进行一些操作。这个程序运行一下,很快就内存溢出了。

    这里明显存在一个反模式:流失监听者泄露(Lapsed Listener Leak)。 由于B类的对象的生命周期比较短,如果在系统运行过程中,大量生成B类的对象,而B的构造函数中有将自己作为监听器加入A的监听器列表中,导致B类的对象无法被垃圾回收器回收。在这里,B自己作为监听器,错误看起来比较明显,但如果用内部匿名类的实现方式:

     

    public B(A a,int id) {
                this.id = id;
                this.a = a;
                this.a.addListener(new PropertyChangeListener() {
                    @Override
                    public void propertyChange(PropertyChangeEvent evt) {
                        System.out.println("on B-" B.this.id "(" evt.getPropertyName() "," evt.getOldValue() "," evt.getNewValue() ")");
                    }
                });
            }
    

     

    代码片段2

    看起来虽然没那么明显,但效果是一样的。因为匿名类的对象会引用自己的父对象。

     

    这个反模式在Java用户界面框架(AWT,Swing)使用的过程中出现的比较多,但没出现问题的原因主要有两个:1.桌面软件的运行时间一般不会太长,很少有需要7X24运行的。2.桌面类软件中的组件数目有限,一般也不会导致内存溢出。但如果是服务器端的程序就没这么幸运了。

    《Bitter Java》中给出了三种解决方案:

    1.显式的删除监听者

    在A中增加removeListener接口,当B的生命周期结束后,将其从A的监听器列表里删除。

    2.缩短锚的生命周期

    确保A类对象的生命周期不要太长,A类的对象如果能尽快被垃圾回收器回收,内存泄露也就不会发生了。

    3.弱化引用

    用弱引用(WeakReference)关联监听器。弱引用的好处是,如果垃圾回收器检测到一个对象当前只有弱引用,就认为该对象可以被回收了。下面是用弱引用重构后的实例代码:

     

    public class LapsedListenerTest2 {
    
        public static class A{
            private List listeners = new CopyOnWriteArrayList();
            private String name;
            public A(String name) {
                this.name = name;
            }
            public void addListener(PropertyChangeListener listener) {
                listeners.add(new WeakReference(listener));
            }
            private void fire(String property,Object oldValue,Object newValue) {
                for(WeakReference listenerRef:listeners) {
                    PropertyChangeListener listener = listenerRef.get();
                    if(listener != null) {
                        listenerRef.get().propertyChange(new PropertyChangeEvent(this, property, oldValue, newValue));
                    }else {
                        listeners.remove(listenerRef);
                    }
                }
            }
            public void setName(String name) {
                String oldName = this.name;
                this.name = name;
                fire("name", oldName, name);
            }
        }
    
        public static class B implements PropertyChangeListener{
            private int id;
            private A a;
            private byte[] bt= new byte[1024*1024];
    
            public B(A a,int id) {
                this.id = id;
                this.a = a;
                this.a.addListener(this);
            }
            @Override
            public void propertyChange(PropertyChangeEvent evt) {
                System.out.println("on B-" B.this.id "(" evt.getPropertyName() "," evt.getOldValue() "," evt.getNewValue() ")");
            }
            @Override
            protected void finalize() throws Throwable {
                System.out.println("finalize:" id);
            }
        }
    
        /**
         * @param args
         * @throws InterruptedException
         */
        public static void main(String[] args) throws InterruptedException {
            A a = new A("A");
            int j = 0;
            B first = null;
            while(true) {
                B b = new B(a,j);
                if(first == null) {
                    first = b;
                }
                //do some thing with b
                a.setName("A" j);
                j  ;
                System.gc();
                Thread.sleep(20);
            }
        }
    }
    

     

    代码片段3

     运行后可以看出:

    由于first引用了第一个B对象,致使该对象一直存活,而其他的B对象都被很快的回收了。是不是一个完美的解决方案?别着急,这儿还有个问题。如果B类采用匿名类监听器的情况呢?(代码片段2的情况)

    这样的情况下,所有的监听器都只有弱引用,导致监听器会很快被垃圾回收器回收,即便是B类的对象存活(first)的情况下!所以这种方式要求监听器在A类外部必须还有个引用,并且该引用的生命周期与B一致(B自己或者B的属性)。

    综合看来,还是方案1比较可靠,虽然要考手动操作。按照方案1的重构:

     

    public class LapsedListenerTest {
    
        public static class A{
            private List listeners = new CopyOnWriteArrayList();
            private String name;
            public A(String name) {
                this.name = name;
            }
            public void addListener(PropertyChangeListener listener) {
                listeners.add(listener);
            }
            public void removeListener(PropertyChangeListener listener) {
                listeners.remove(listener);
            }
            private void fire(String property,Object oldValue,Object newValue) {
                for(PropertyChangeListener listener:listeners) {
                        listener.propertyChange(new PropertyChangeEvent(this, property, oldValue, newValue));
                }
            }
            public void setName(String name) {
                String oldName = this.name;
                this.name = name;
                fire("name", oldName, name);
            }
        }
    
        public static class B implements PropertyChangeListener{
            private int id;
            private A a;
            //占用内存
            private byte[] bt= new byte[1024*1024];
            public B(A a,int id) {
                this.id = id;
                this.a = a;
                this.a.addListener(this);
            }
    
            @Override
            public void propertyChange(PropertyChangeEvent evt) {
                System.out.println("on B-" B.this.id "(" evt.getPropertyName() "," evt.getOldValue() "," evt.getNewValue() ")");
            }
    
            public void dispose() {
                this.a.removeListener(this);
            }
    
        }
    
        /**
         * @param args
         * @throws InterruptedException
         */
        public static void main(String[] args) throws InterruptedException {
            A a = new A("A");
            int j = 0;
            while(true) {
                B b = new B(a,j);
                //do some thing with b
                a.setName("A" j);
                b.dispose();
                j  ;
                System.gc();
                Thread.sleep(20);
            }
        }
    
    }
    

     

     

    代码片段4

     

    本方案的缺点就是必须显式调用下b.dispose()进行销毁。

    不知道还有没有其他的更好的解决方案?

     

  • linux kde 声音问题

    升级了一下kde,然后系统声音就时好时坏,老出现 “phonon 回放设备不工作 “的提示,很是郁闷。

    查了下网上,说是要设置下 多媒体的回放设备

    但点击 系统设置->多媒体(System Setting->Multimedia),设置窗口立刻崩溃(crash).

    显示错误: kcm_phonon.so: undefined symbol: _ZNK6Phonon12GlobalConfig19hideAdvancedDevicesEv

    amarok不能播放音乐。

    网上查了一下,应该是Phonon的问题

    Phonon是什么?Qt从4.4版本开始提供的一套多媒体框架,提供多媒体回放的功能。(phonon的图解说明:http://c-home.appspot.com/2009/03/2/phonon_pic.html

    检查了下系统 Phonon  *的版本,发现 Phonon的版本与kde不兼容。升级了下phonon,这个问题就不存在了。
    *

    如果声音还有问题,根据下面这篇文档设置下ALSA:

    http://wiki.archlinux.org/index.php/Advanced_Linux_Sound_Architecture

    最后还有一个问题:flash没有声音,无论用什么浏览器。

    搜索了一下,是PulseAudio的问题。

    PulseAudio is a sound server for POSIX and Win32 systems

    参考下面两篇文档的设置:

    http://developer.novell.com/wiki/index.php/Feisty/HOWTO:_PulseAudio

    http://ubuntuforums.org/showthread.php?t=789578

  • 终于在网上建了个家

    记得我刚开始学网页就是一个简单的想法,给自己弄个个人站。

    于是开始学习
    html,css,photoshop,dreamweaver,javascript,flash。然后又知道用静态html做出来的
    网站很难维护,最好是用程序做成动态的。于是又学习asp,php,数据库,java,linux。结果这一下误入歧途,回不来了。法律专业也不搞了,转行写程序了。几年来给别人也做了好些网站程序,但自己最初的那个想法还没实现。本来是想抽空自己写个简单的个人博客用的,但这个想法一直处于构想当中。最
    后还是找个现成的单用户blog程序吧。既然喜欢java,那也应该找个java的。找来找去,就找到了这个blog程序—pebble,官方网站
    – 。咱买不起房子,但在网上给自己搭个家还行吧。

    pebble的数据采用xml方式储存,没有用数据库,搭建方便,功能也不错。

    对中文支持完全没问题。刚搭建之后,发现查询中文tag的时候会有乱码问题,它的url路径里出现中文了:http://jolestar.com/tags/开源项目/.但后来才发现那是我的mod_jk的配置问题。应该加上

    JkOptions  ForwardURICompatUnparsed  ForwardDirectories
    

    这两项。第一项是让apache不要解码,把url提交给tomcat处理。第二项是让apache把目录直接提交给tomcat处理。

    这样就没问题了。

    好了,开始转我的博客吧。但刚一转就发现,编辑器少个功能:插入代码。pebble默认是用FCKEditor编辑器,弄了一下,发现FCKEditor的插件体系不好,网上找到的FCKEditor的代码插入插件都不太好用,很多是直接把代码格式化成html的格式高亮。这种方式不好,因为这样格式化,用户复制代码的时候会很不方便,会复制上冗余的东西,以后编辑也不方便。好的方式就是用js动态实现高亮,而不是直接用html格式化。看了一下javaeye的代码插入功能,觉得不错。javaeye的编辑器用的是tiny_mce,于是就把博客的编辑器替换成了tiny_mce,又把javaeye的tiny_mce的代码插入插件搬了过来。嘿,还挺好用。在此感谢javaeye。

    代码插件有了,然后就是代码高亮。javaeye用的是SyntaxHighlighter, http://alexgorbatchev.com ,但它好像用的是旧版本,或者是它的修改版本,不太好用。于是下载了最新的SyntaxHighlighter,实验了一下,嘿,效果不错。但又发现一个问题。新版本的SyntaxHighlighter把每种语言的高亮js都放在单独文件里,必须提前把需要用到的需要高亮的语言的js都加载进来。但页面模板里没法知道博客的内容会插入那些语言的代码,如果把所有的语言的js都加载进来,会严重影响页面加载速度。于是又写了个动态加载语言js的脚本。

    var syntaxhighlighter_url = "/scripts/syntaxhighlighter/";
      var brushLibs = {js:"JScript",jscript:"JScript",javascript:"JScript",
    		  bash:"Bash",shell:"Bash",css:"Css",actionscript3:"AS3",as3:"AS3",cpp:"Cpp",c:"Cpp",
    		  csharp:"CSharp",groovy:"Groovy",java:"Java",javafx:"JavaFX",jfx:"JavaFX",
    		  perl:"Perl",pl:"Perl",php:"Php",text:"Plain",plain:"Plain",
                     py:"Python",python:"Python",
    		  ruby:"Ruby",ror:"Ruby",rails:"Ruby",scala:"Scala",sql:"Sql",xml:"Xml",html:"Xml",
                     xhtml:"Xml",xslt:"Xml"
    		  };
      function loadBrushLibs(){
    	  var pres = document.getElementsByTagName("pre");
    	  for(var i=0;i
    

subscribe via RSS