• 设计让生活更美好

        设计让生活更美好–套用下SB会的口号。

     

    设计心理学

    Read more...
  • 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

subscribe via RSS