JavaScript基本包装类型

var falseObject = new Boolean(false);
var result3 = falseObject && true;
alert(result3); // true

var falseValue = false;
result4 = falseValue && true;
alert(result4); // false

alert(typeof falseObject); // object
alert(typeof falseValue); // boolean
alert(falseObject instanceof Boolean); // true
alert(falseValue instanceof Boolean); // false

在这个例子中,我们使用false值创建了一个Boolean对象。然后,将这个对象与基本类型值true构成了逻辑与表达式。在布尔运算中,false && true等于false。可是,示例中的这行代码是对falseObject而不是对它的值(false)进行求值布尔表达式中的所有对象都会被转换为true,因此falseObject对象在布尔表达式中代表的是true。

var num = 10;
alert(num.toString());
alert(num.toString(2));
alert(num.toString(8));
alert(num.toString(10));
alert(num.toString(16));

告诉它返回几进制数值的字符串形式

Reference

2015/10/25

JavaScript垃圾回收

JavaScript垃圾回收

标记清楚

JavaScript中最常用的垃圾收集方式是标记清楚(mark-and-sweep)。当变量进入环境时,就将这个变量标记为“进入环境”。从逻辑上讲,永远不能释放进入环境的变量所占用的内存,因为只要执行流进入相应的环境,就可能会用到它们。而当变量离开环境时,则将其标记为“离开环境”。

引用计数

另一种不太常见的垃圾收集策略叫做引用计数(reference counting)。引用计数的含义是跟踪记录每个值被引用的次数。当声明了一个变量并将一个引用类型值赋给该变量时,则这个值的引用次数就是1.如果同一个值又被赋给另一个变量,则该值的引用次数加1.

有一个严重的问题:循环引用。循环引用指的是对象A中包含一个指向对象B的指针,而对象B中也包含一个指向对象A的引用,例如:

function problem(){
    var objectA = new Object();
    var objectB = new Object();

    objectA.someOtherObject = objectB;
    objectB.anotherObject = objectA;
}

在这个例子中,objectA和objectB通过各自的属性相互引用

IE中有一部分并不是原生JavaScript对象。例如,其BOM和DOM中的对象就是使用C++以COM对象的形式实现的,而COM对象的垃圾收集机制采用的就是引用计数策略。

var element = document.getElementById("some_element");
var myObject = new Object();
myObject.element = element;
element.someObject = myObject;

为了避免类似这种循环引用问题,最好是在不使用它们的时候手工断开

myObject.element = null;
element.someObject = null;

性能问题

IE的垃圾收集器是根据内存分配量运行的,具体一点就是256个变量,4096个对象(或数组)字面量和数组元素(slot)或者64KB的字符串。达到上述任何一个临界值,垃圾回收器就会运行。

这种实现方式的问题在于,如果一个脚本中包含那么多变量,那么该脚本很可能会在其生命周期中一直保有那么多的变量。而这样一来,垃圾收集器就不得不频繁地运行。结果,由此引发了严重性能问题促使IE7重写了其垃圾收集例程。

管理内存

分配给Web浏览器的可用内存数量通常要比分配给桌面程序的少。这样做的目的主要是出于安全方面的考虑,目的是防止运行JavaScript的网页耗尽全部系统内存而导致系统崩溃。

Reference

2015/10/25

JavaScript垃圾回收

JavaScript垃圾回收

标记清楚

JavaScript中最常用的垃圾收集方式是标记清楚(mark-and-sweep)。当变量进入环境时,就将这个变量标记为“进入环境”。从逻辑上讲,永远不能释放进入环境的变量所占用的内存,因为只要执行流进入相应的环境,就可能会用到它们。而当变量离开环境时,则将其标记为“离开环境”。

引用计数

另一种不太常见的垃圾收集策略叫做引用计数(reference counting)。引用计数的含义是跟踪记录每个值被引用的次数。当声明了一个变量并将一个引用类型值赋给该变量时,则这个值的引用次数就是1.如果同一个值又被赋给另一个变量,则该值的引用次数加1.

有一个严重的问题:循环引用。循环引用指的是对象A中包含一个指向对象B的指针,而对象B中也包含一个指向对象A的引用,例如:

function problem(){
    var objectA = new Object();
    var objectB = new Object();

    objectA.someOtherObject = objectB;
    objectB.anotherObject = objectA;
}

在这个例子中,objectA和objectB通过各自的属性相互引用

IE中有一部分并不是原生JavaScript对象。例如,其BOM和DOM中的对象就是使用C++以COM对象的形式实现的,而COM对象的垃圾收集机制采用的就是引用计数策略。

var element = document.getElementById("some_element");
var myObject = new Object();
myObject.element = element;
element.someObject = myObject;

为了避免类似这种循环引用问题,最好是在不使用它们的时候手工断开

myObject.element = null;
element.someObject = null;

性能问题

IE的垃圾收集器是根据内存分配量运行的,具体一点就是256个变量,4096个对象(或数组)字面量和数组元素(slot)或者64KB的字符串。达到上述任何一个临界值,垃圾回收器就会运行。

这种实现方式的问题在于,如果一个脚本中包含那么多变量,那么该脚本很可能会在其生命周期中一直保有那么多的变量。而这样一来,垃圾收集器就不得不频繁地运行。结果,由此引发了严重性能问题促使IE7重写了其垃圾收集例程。

管理内存

分配给Web浏览器的可用内存数量通常要比分配给桌面程序的少。这样做的目的主要是出于安全方面的考虑,目的是防止运行JavaScript的网页耗尽全部系统内存而导致系统崩溃。

Reference

2015/10/25

Java NIO杂4

Java NIO中的SocketChannel是一个连接到TCP网络套接字的通道。可以通过以下两种方式创建SocketChannel:

  • 打开一个SocketChannel并连接到互联网上的某台服务器
  • 一个新连接到达ServerSocketChannel时,会创建一个SocketChannel
打开SocketChannel
SocketChannel socketChannel = SocketChannel.open();
socketChannel.connect(new InetSocketAddress("http://jenkov.com", 80));
关闭SocketChannel
socketChannel.close();
从SocketChannel读取数据
ByteBuffer buf = ByteBuffer.allocate(48);
int bytesRead = socketChannel.read(buf);

首先,分配一个Buffer。从SocketChannel读取到的数据将会放到这个Buffer中。

然后,调用SocketChannel.read()。该方法将数据从SocketChannel读到Buffer中。

read()方法返回的int值表示读了多少字节进Buffer里。如果返回的是-1,表示已经读到了流的末尾(连接关闭了)。

写入SocketChannel

写数据到SocketChannel用的是SocketChannel.write()方法,该方法以一个Buffer作为参数

String newData = "New String to write to file..." + System.currentTimeMillis();

ByteBuffer buf = ByteBuffer.allocate(48);
buf.clear();
buf.put(newData.getBytes());

buf.flip();

while(buf.hasRemaining()) {
    channel.write(buf);
}

SocketChannel.write()方法的调用是在一个while循环中的。Write()方法无法保证能写多少字节到SocketChannel。所以,我们重复调用write()直到Buffer没有要写的字节为止。

非阻塞模式

可以设置SocketChannel为非阻塞模式(non-blocking mode)。设置之后,就可以在异步模式下调用connect(), read()write()了。

connect()

如果SocketChannel在非阻塞模式下,此时调用connect(),该方法可能在连接建立之前就返回了。为了确定连接是否建立,可以调用finishConnect()的方法。

socketChannel.configureBlocking(false);
socketChannel.connect(new InetSocketAddress("http://jenkov.com", 80));

while(! socketChannel.finishConnect() ){
    //wait, or do something else...
}
write()

非阻塞模式下,write()方法在尚未写出任何内容时可能就返回了。所以需要在循环中调用write()

read()

非阻塞模式下,read()方法在尚未读取到任何数据时可能就返回了。所以需要关注它的int返回值,它会告诉你读取了多少字节。

ServerSocketChannel

ServerSocketChannel serverSocketChannel = ServerSocketChannel.open();

serverSocketChannel.socket().bind(new InetSocketAddress(9999));

while(true){
    SocketChannel socketChannel =
            serverSocketChannel.accept();

    //do something with socketChannel...
}
打开ServerSocketChannel

通过调用ServerSocketChannel.open()方法来打开ServerSocketChannel

ServerSocketChannel serverSocketChannel = ServerSocketChannel.open();
关闭ServerSocketChannel
serverSocketChannel.close();
监听新进来的连接

通过ServerSocketChannel.accept()方法监听新进来的连接。当accept()方法返回的时候,它返回一个包含新进来的连接的 SocketChannel。因此, accept()方法会一直阻塞到有新连接到达

通常不会仅仅只监听一个连接,在while循环中调用 accept()方法

while(true){
    SocketChannel socketChannel =
            serverSocketChannel.accept();

    //do something with socketChannel...
}

非阻塞模式

ServerSocketChannel可以设置成非阻塞模式。在非阻塞模式下,accept()方法会立刻返回,如果还没有新进来的连接,返回的将是null。 因此,需要检查返回的SocketChannel是否是null.

ServerSocketChannel serverSocketChannel = ServerSocketChannel.open();

serverSocketChannel.socket().bind(new InetSocketAddress(9999));
serverSocketChannel.configureBlocking(false);

while(true){
    SocketChannel socketChannel = serverSocketChannel.accept();

    if(socketChannel != null){
        //do something with socketChannel...
    }
}

Reference

http://ifeve.com/socket-channel/

2015/10/25

Java NIO杂3

Java NIO中的FileChannel是一个连接到文件的通道。可以通过文件通道读写文件。

FileChannel无法设置为非阻塞模式,它总是运行在阻塞模式下。

打开FileChannel

在使用FileChannel之前,必须先打开它。

RandomAccessFile aFile = new RandomAccessFile("data/nio-data.txt", "rw");
FileChannel inChannel = aFile.getChannel();

从FileChannel读取数据

调用多个read()方法之一从FileChannel中读取数据

ByteBuffer buf = ByteBuffer.allocate(48);
int bytesRead = inChannel.read(buf);

首先,分配一个Buffer。从FileChannel中读取的数据将被读到Buffer中。

然后,调用FileChannel.read()方法。该方法将数据从FileChannel读取到Buffer中。

read()方法返回的int值表示了有多少字节被读到了Buffer中。如果返回-1,表示到了文件末尾。

向FileChannel写数据

使用FileChannel.write()方法向FileChannel写数据,该方法的参数是一个Buffer

String newData = "New String to write to file..." + System.currentTimeMillis();

ByteBuffer buf = ByteBuffer.allocate(48);
buf.clear();
buf.put(newData.getBytes());

buf.flip();

while(buf.hasRemaining()) {
    channel.write(buf);
}

注意FileChannel.write()是在while循环中调用的。因为无法保证write()方法一次能向FileChannel写入多少字节,因此需要重复调用write()方法,直到Buffer中已经没有尚未写入通道的字节。

关闭FileChannel

用完FileChannel后必须将其关闭。如:

channel.close();
FileChannel的position方法

有时可能需要在FileChannel的某个特定位置进行数据的读/写操作。可以通过调用position()方法获取FileChannel的当前位置。

也可以通过调用position(long pos)方法设置FileChannel的当前位置

long pos = channel.position();
channel.position(pos +123);
FileChannel的size方法

FileChannel实例的size()方法将返回该实例所关联文件的大小。如:

long fileSize = channel.size();
FileChannel的truncate方法

可以使用FileChannel.truncate()方法截取一个文件。截取文件时,文件将中指定长度后面的部分将被删除。如:

channel.truncate(1024);

这个例子截取文件的前1024个字节。

FileChannel的force方法

FileChannel.force()方法将通道里尚未写入磁盘的数据强制写到磁盘上。

出于性能方面的考虑,操作系统会将数据缓存在内存中,所以无法保证写入到FileChannel里的数据一定会即时写到磁盘上。要保证这一点,需要调用force()方法

force()方法有一个boolean类型的参数,指明是否同时将文件元数据(权限信息等)写到磁盘上。

下面的例子同时将文件数据和元数据强制写到磁盘上:

channel.force(true);

Reference

http://ifeve.com/file-channel/

2015/10/25