http://windowsvistablog.com/
这里有Vista最新奇最及时的消息。
2007年4月29日星期日
2007年4月25日星期三
内存错误-原理角度·A Programmer's Perspective_转载
-----------------作者: 林锐 博士 (稍有整合改动)
对于程序员来说内存是一片危机四伏的沼泽(当然这在JAVA和CLR程序中已经大为改观)。
比尔·盖茨也失言了:640K ought to be enough for everybody。当前内存连Desktop也普遍标配1GB的容量。不仅容量,内存管理的复杂度也在提升,只不过随着软件的进化,不断地分层,有些问题对于不同层面的开发人员透明了。
程序员们经常编写内存管理程序,往往提心吊胆。如果不想触雷,唯一的解决办法就是发现所有潜伏的地雷并且排除它们,躲是躲不了的。本文的内容比一般教科书的要深入得多,读者需细心阅读,做到真正地通晓内存管理。
局部变量的存储单元都可以在栈上创建,函数执行结束时这些存储单元自动被释放。栈内存分配运算内置于处理器的指令集中,效率很高,但是分配的内存容量有限。
从堆上分配,亦称动态内存分配。程序在运行的时候用malloc或new申请任意多少的内存,程序员自己负责在何时用free或delete释放内存。动态内存的生存期由我们决定,使用非常灵活,但问题也最多。
常见的内存错误及其对策
发生内存错误是件非常麻烦的事情。编译器不能自动发现这些错误,通常是在程序运行时才能捕捉到。而这些错误大多没有明显的症状,时隐时现,增加了改错的难度。有时用户怒气冲冲地把你找来,程序却没有发生任何问题,你一走,错误又发作了。
常见的内存错误及其对策如下:
1.内存分配未成功,却使用了它。
编程新手常犯这种错误,因为他们没有意识到内存分配会不成功。常用解决办法是,在使用内存之前检查指针是否为NULL。如果指针p是函数的参数,那么在函数的入口处用assert(p!=NULL)进行检查。如果是用malloc或new来申请内存,应该用if(p==NULL) 或if(p!=NULL)进行防错处理。
2.内存分配虽然成功,但是尚未初始化就引用它。
犯这种错误主要有两个起因:一是没有初始化的观念;二是误以为内存的缺省初值全为零,导致引用初值错误(例如数组)。
内存的缺省初值究竟是什么并没有统一的标准,尽管有些时候为零值,我们宁可信其无不可信其有。所以无论用何种方式创建数组,都别忘了赋初值,即便是赋零值也不可省略,不要嫌麻烦。
3.内存分配成功并且已经初始化,但操作越过了内存的边界。
例如在使用数组时经常发生下标“多1”或者“少1”的操作。特别是在for循环语句中,循环次数很容易搞错,导致数组操作越界。
4.忘记了释放内存,造成内存泄露。
含有这种错误的函数每被调用一次就丢失一块内存。刚开始时系统的内存充足,你看不到错误。终有一次程序突然死掉,系统出现提示:内存耗尽。
动态内存的申请与释放必须配对,程序中malloc与free的使用次数一定要相同,否则肯定有错误(new/delete同理)。
5.释放了内存却继续使用它。
有三种情况:
(1)程序中的对象调用关系过于复杂,实在难以搞清楚某个对象究竟是否已经释放了内存,此时应该重新设计数据结构,从根本上解决对象管理的混乱局面。
(2)函数的return语句写错了,注意不要返回指向“栈内存”的“指针”或者“引用”,因为该内存在函数体结束时被自动销毁。
(3)使用free或delete释放了内存后,没有将指针设置为NULL。导致产生“野指针”。
Summary,我们要注意:
1.用malloc或new申请内存之后,应该立即检查指针值是否为NULL。防止使用指针值为NULL的内存;
2.不要忘记为数组和动态内存赋初值。防止将未被初始化的内存作为右值使用;
3.避免数组或指针的下标越界,特别要当心发生“多1”或者“少1”操作;
4.动态内存的申请与释放必须配对,防止内存泄漏;
5.用free或delete释放了内存之后,立即将指针设置为NULL,防止产生“野指针”。
下面举几个经典的错误例子,大家不要犯同样的错误:
1. 返回栈内存指针
char *GetString(void)
{
char *p = "hello world";
return p;
}
char* pGet = GetString();
这段程序编译时没有错误,运行也没有错误,但是你却无法使得返回的pGet指针指向的数据是你想要的“hello world”,因为指针p的生命期是函数GetString内,运行完函数GetString后,p分配的栈空间马上被系统回收了。虽然pGet指向了p当初分配的内存地址,但是那块地址已经没有内容了。
2.这是一个出现频率非常高的错误
char* pChar = new char;
……
int a ;
pChar = &a;
……
delete pChar;
当然这是一个例子,具体的程序各有不同。
这段程序有两个问题。一是pChar = &a;将导致pChar原先分配的空间无法再被获取,就象我们的丢失了朋友的电话号码一样,无法再联系这个朋友了。这就造成了内存泄漏。如果内存泄漏多了,可能导致系统的崩溃,因为可用的资源将越来越少,直到枯竭为止。第二个问题是delete pChar将导致异常发生,因为这时的pChar已经不是指向动态分配的内存了,而是指向了a分配的栈空间,而栈空间是不能使用delete来回收的,因此将导致内存异常。
对于程序员来说内存是一片危机四伏的沼泽(当然这在JAVA和CLR程序中已经大为改观)。
比尔·盖茨也失言了:640K ought to be enough for everybody。当前内存连Desktop也普遍标配1GB的容量。不仅容量,内存管理的复杂度也在提升,只不过随着软件的进化,不断地分层,有些问题对于不同层面的开发人员透明了。
程序员们经常编写内存管理程序,往往提心吊胆。如果不想触雷,唯一的解决办法就是发现所有潜伏的地雷并且排除它们,躲是躲不了的。本文的内容比一般教科书的要深入得多,读者需细心阅读,做到真正地通晓内存管理。
局部变量的存储单元都可以在栈上创建,函数执行结束时这些存储单元自动被释放。栈内存分配运算内置于处理器的指令集中,效率很高,但是分配的内存容量有限。
从堆上分配,亦称动态内存分配。程序在运行的时候用malloc或new申请任意多少的内存,程序员自己负责在何时用free或delete释放内存。动态内存的生存期由我们决定,使用非常灵活,但问题也最多。
常见的内存错误及其对策
发生内存错误是件非常麻烦的事情。编译器不能自动发现这些错误,通常是在程序运行时才能捕捉到。而这些错误大多没有明显的症状,时隐时现,增加了改错的难度。有时用户怒气冲冲地把你找来,程序却没有发生任何问题,你一走,错误又发作了。
常见的内存错误及其对策如下:
1.内存分配未成功,却使用了它。
编程新手常犯这种错误,因为他们没有意识到内存分配会不成功。常用解决办法是,在使用内存之前检查指针是否为NULL。如果指针p是函数的参数,那么在函数的入口处用assert(p!=NULL)进行检查。如果是用malloc或new来申请内存,应该用if(p==NULL) 或if(p!=NULL)进行防错处理。
2.内存分配虽然成功,但是尚未初始化就引用它。
犯这种错误主要有两个起因:一是没有初始化的观念;二是误以为内存的缺省初值全为零,导致引用初值错误(例如数组)。
内存的缺省初值究竟是什么并没有统一的标准,尽管有些时候为零值,我们宁可信其无不可信其有。所以无论用何种方式创建数组,都别忘了赋初值,即便是赋零值也不可省略,不要嫌麻烦。
3.内存分配成功并且已经初始化,但操作越过了内存的边界。
例如在使用数组时经常发生下标“多1”或者“少1”的操作。特别是在for循环语句中,循环次数很容易搞错,导致数组操作越界。
4.忘记了释放内存,造成内存泄露。
含有这种错误的函数每被调用一次就丢失一块内存。刚开始时系统的内存充足,你看不到错误。终有一次程序突然死掉,系统出现提示:内存耗尽。
动态内存的申请与释放必须配对,程序中malloc与free的使用次数一定要相同,否则肯定有错误(new/delete同理)。
5.释放了内存却继续使用它。
有三种情况:
(1)程序中的对象调用关系过于复杂,实在难以搞清楚某个对象究竟是否已经释放了内存,此时应该重新设计数据结构,从根本上解决对象管理的混乱局面。
(2)函数的return语句写错了,注意不要返回指向“栈内存”的“指针”或者“引用”,因为该内存在函数体结束时被自动销毁。
(3)使用free或delete释放了内存后,没有将指针设置为NULL。导致产生“野指针”。
Summary,我们要注意:
1.用malloc或new申请内存之后,应该立即检查指针值是否为NULL。防止使用指针值为NULL的内存;
2.不要忘记为数组和动态内存赋初值。防止将未被初始化的内存作为右值使用;
3.避免数组或指针的下标越界,特别要当心发生“多1”或者“少1”操作;
4.动态内存的申请与释放必须配对,防止内存泄漏;
5.用free或delete释放了内存之后,立即将指针设置为NULL,防止产生“野指针”。
下面举几个经典的错误例子,大家不要犯同样的错误:
1. 返回栈内存指针
char *GetString(void)
{
char *p = "hello world";
return p;
}
char* pGet = GetString();
这段程序编译时没有错误,运行也没有错误,但是你却无法使得返回的pGet指针指向的数据是你想要的“hello world”,因为指针p的生命期是函数GetString内,运行完函数GetString后,p分配的栈空间马上被系统回收了。虽然pGet指向了p当初分配的内存地址,但是那块地址已经没有内容了。
2.这是一个出现频率非常高的错误
char* pChar = new char;
……
int a ;
pChar = &a;
……
delete pChar;
当然这是一个例子,具体的程序各有不同。
这段程序有两个问题。一是pChar = &a;将导致pChar原先分配的空间无法再被获取,就象我们的丢失了朋友的电话号码一样,无法再联系这个朋友了。这就造成了内存泄漏。如果内存泄漏多了,可能导致系统的崩溃,因为可用的资源将越来越少,直到枯竭为止。第二个问题是delete pChar将导致异常发生,因为这时的pChar已经不是指向动态分配的内存了,而是指向了a分配的栈空间,而栈空间是不能使用delete来回收的,因此将导致内存异常。
内存错误-应用角度·A Programmer's Perspective_整理资料
使用Windows操作系统的人有时会遇到这样的错误信息:“0X????????指令引用的0x00000000内存,该内存不能written”,然后应用程序被关闭。如果去请教一些“高手”,得到的回答往往是“Windows就是这样不稳定”之类的义愤和不屑。其实,这个错误并不一定是Windows不稳定造成的。下面我们就来简单分析这种错误的常见原因。
一、应用程序没有检查内存分配失败
程序需要一块内存用以保存数据时,就需要调用操作系统提供的“功能函数”来申请,如果内存分配成功,函数就会将所新开辟的内存区地址返回给应用程序,应用程序就可以通过这个地址使用这块内存。这就是“动态内存分配”,内存地址也就是编程中的“指针”。
内存不是永远都招之即来、用之不尽的,有时候内存分配也会失败。当分配失败时系统函数会返回一个0值,这时返回值“0”已不表示新启用的指针,而是系统向应用程序发出的一个通知,告知出现了错误。作为应用程序,在每一次申请内存后都应该检查返回值是否为0,如果是,则意味着出现了故障,应该采取一些措施挽救,这就增强了程序的“健壮性”。
若应用程序没有检查这个错误,它就会按照“思维惯性”认为这个值是给它分配的可用指针,继续在之后的运行中使用这块内存。真正的0地址内存区保存的是计算机系统中最重要的“中断描述符表”,绝对不允许应用程序使用。在没有保护机制的操作系统下(如DOS),写数据到这个地址会导致立即死机,而在健壮的操作系统中,如Windows等,这个操作会马上被系统的保护机制捕获,其结果就是由操作系统强行关闭出错的应用程序,以防止其错误扩大。这时候,就会出现上述的“写内存”错误,并指出被引用的内存地址为“0x00000000”。
内存分配失败故障的原因很多,内存不够、系统函数的版本不匹配等都可能有影响。因此,这种分配失败多见于操作系统使用很长时间后,安装了多种应用程序(包括无意中“安装”的病毒程序),更改了大量的系统参数和系统文件之后。
二、应用程序由于自身BUG引用了不正常的内存指针
在使用动态分配的应用程序中,有时会有这样的情况出现:程序试图读写一块“应该可用”的内存,但不知为什么,这个预料中可用的指针已经失效了。有可能是“忘记了”向操作系统要求分配,也可能是程序自己在某个时候已经注销了这块内存而“没有留意”等等。注销了的内存被系统回收,其访问权已经不属于该应用程序,因此读写操作也同样会触发系统的保护机制,企图“违法”的程序唯一的下场就是被操作终止运行,回收全部资源。计算机世界的法律还是要比人类有效和严厉得多啊!
像这样的情况都属于程序自身的BUG,你往往可在特定的操作顺序下重现错误。无效指针不一定总是0,因此错误提示中的内存地址也不一定为“0x00000000”,而是其他随机数字。
一、应用程序没有检查内存分配失败
程序需要一块内存用以保存数据时,就需要调用操作系统提供的“功能函数”来申请,如果内存分配成功,函数就会将所新开辟的内存区地址返回给应用程序,应用程序就可以通过这个地址使用这块内存。这就是“动态内存分配”,内存地址也就是编程中的“指针”。
内存不是永远都招之即来、用之不尽的,有时候内存分配也会失败。当分配失败时系统函数会返回一个0值,这时返回值“0”已不表示新启用的指针,而是系统向应用程序发出的一个通知,告知出现了错误。作为应用程序,在每一次申请内存后都应该检查返回值是否为0,如果是,则意味着出现了故障,应该采取一些措施挽救,这就增强了程序的“健壮性”。
若应用程序没有检查这个错误,它就会按照“思维惯性”认为这个值是给它分配的可用指针,继续在之后的运行中使用这块内存。真正的0地址内存区保存的是计算机系统中最重要的“中断描述符表”,绝对不允许应用程序使用。在没有保护机制的操作系统下(如DOS),写数据到这个地址会导致立即死机,而在健壮的操作系统中,如Windows等,这个操作会马上被系统的保护机制捕获,其结果就是由操作系统强行关闭出错的应用程序,以防止其错误扩大。这时候,就会出现上述的“写内存”错误,并指出被引用的内存地址为“0x00000000”。
内存分配失败故障的原因很多,内存不够、系统函数的版本不匹配等都可能有影响。因此,这种分配失败多见于操作系统使用很长时间后,安装了多种应用程序(包括无意中“安装”的病毒程序),更改了大量的系统参数和系统文件之后。
二、应用程序由于自身BUG引用了不正常的内存指针
在使用动态分配的应用程序中,有时会有这样的情况出现:程序试图读写一块“应该可用”的内存,但不知为什么,这个预料中可用的指针已经失效了。有可能是“忘记了”向操作系统要求分配,也可能是程序自己在某个时候已经注销了这块内存而“没有留意”等等。注销了的内存被系统回收,其访问权已经不属于该应用程序,因此读写操作也同样会触发系统的保护机制,企图“违法”的程序唯一的下场就是被操作终止运行,回收全部资源。计算机世界的法律还是要比人类有效和严厉得多啊!
像这样的情况都属于程序自身的BUG,你往往可在特定的操作顺序下重现错误。无效指针不一定总是0,因此错误提示中的内存地址也不一定为“0x00000000”,而是其他随机数字。
VC MFC之“stdafx.h”释疑
author:nforcex
所谓头文件预编译,就是把一个工程(Project)中使用的一些MFC标准头文件(如Windows.H、Afxwin.H)预先编译,以后该工程编译时,不再编译这部分头文件,仅仅使用预编译的结果。这样可以加快编译速度,节省时间。预编译头文件通过编译stdafx.cpp生成,以工程名命名,由于预编译的头文件的后缀是“pch”,所以编译结果文件是projectname.pch。
编译器通过一个头文件stdafx.h来使用预编译头文件。stdafx.h这个头文件名是可以在project的编译设置里指定的。编译器认为,所有在指令#include "stdafx.h"前的代码都是预编译的,它跳过#include "stdafx. h"指令,使用projectname.pch编译这条指令之后的所有代码。因此,所有的CPP实现文件第一条语句都是:#include "stdafx.h"。
换句话说:Stdafx.cpp是一个只有一条语句(#include "stdafx.h")的空文件;Stdafx.h是Visual C++为每个项目配置的用来预编译的文件,在Stdafx.h文件中可以加入应用程序所需的头文件;那有人会问afx是什么意思? afx是Application Framework 的缩写,afx_ 泛指MFC中的全局变量和全局函数,af 就是 application framework,x添进去为了凑出三个字母吧。
所谓头文件预编译,就是把一个工程(Project)中使用的一些MFC标准头文件(如Windows.H、Afxwin.H)预先编译,以后该工程编译时,不再编译这部分头文件,仅仅使用预编译的结果。这样可以加快编译速度,节省时间。预编译头文件通过编译stdafx.cpp生成,以工程名命名,由于预编译的头文件的后缀是“pch”,所以编译结果文件是projectname.pch。
编译器通过一个头文件stdafx.h来使用预编译头文件。stdafx.h这个头文件名是可以在project的编译设置里指定的。编译器认为,所有在指令#include "stdafx.h"前的代码都是预编译的,它跳过#include "stdafx. h"指令,使用projectname.pch编译这条指令之后的所有代码。因此,所有的CPP实现文件第一条语句都是:#include "stdafx.h"。
换句话说:Stdafx.cpp是一个只有一条语句(#include "stdafx.h")的空文件;Stdafx.h是Visual C++为每个项目配置的用来预编译的文件,在Stdafx.h文件中可以加入应用程序所需的头文件;那有人会问afx是什么意思? afx是Application Framework 的缩写,afx_ 泛指MFC中的全局变量和全局函数,af 就是 application framework,x添进去为了凑出三个字母吧。
关于Tor
author:nforcex
有个疑问,我的教育网本来就不能连到www.cnn.com等外国网站,许多国外站点都不能连到。用Tor会有用吗?
RE:有用啊,教育网本来是能够访问外国网站的,但因为是基于流量的高额收费方式,高校往往把访问外国的封掉了。Tor,它能够基于底层Socks协议进行加密,它的代理服务器是基于特殊“路由算法”的Sock代理,而非简单的应用层代理或HTTP 层代理。每台使用Tor的PC都是一个“路由节点”,它们之间通过socks代理随机跳转,没有最优路径的算法,所以它可以防止某节点的消失,也可以防止追踪。然后某Client通过捆绑的tor访问网页时,就有Privoxy来将Socks代理转化为http代理,于是我们的浏览器就可以通过tor的“路由世界”来访问封锁的网站了。实际上,通过tor路由路径传输的数据包是采用了TLS 加密[一个类似于安全套接字层 (SSL) 的通用安全性协议]方式,并且它是2~5层的代理(不像普通的http代理为应用层代理,Socks是个电路级的底层网关,是DavidKoblas在 1990年开发的,此后就一直作为Internet RFC标准的开放标准)。
当然,基于Tor仍然可以被潜在[理论上可以被过滤,但是尚未实现部署]的过滤技术过滤掉,这就像是一场竞争比赛,看谁能跑到前面~~~~~~~~~
有个疑问,我的教育网本来就不能连到www.cnn.com等外国网站,许多国外站点都不能连到。用Tor会有用吗?
RE:有用啊,教育网本来是能够访问外国网站的,但因为是基于流量的高额收费方式,高校往往把访问外国的封掉了。Tor,它能够基于底层Socks协议进行加密,它的代理服务器是基于特殊“路由算法”的Sock代理,而非简单的应用层代理或HTTP 层代理。每台使用Tor的PC都是一个“路由节点”,它们之间通过socks代理随机跳转,没有最优路径的算法,所以它可以防止某节点的消失,也可以防止追踪。然后某Client通过捆绑的tor访问网页时,就有Privoxy来将Socks代理转化为http代理,于是我们的浏览器就可以通过tor的“路由世界”来访问封锁的网站了。实际上,通过tor路由路径传输的数据包是采用了TLS 加密[一个类似于安全套接字层 (SSL) 的通用安全性协议]方式,并且它是2~5层的代理(不像普通的http代理为应用层代理,Socks是个电路级的底层网关,是DavidKoblas在 1990年开发的,此后就一直作为Internet RFC标准的开放标准)。
当然,基于Tor仍然可以被潜在[理论上可以被过滤,但是尚未实现部署]的过滤技术过滤掉,这就像是一场竞争比赛,看谁能跑到前面~~~~~~~~~
2007年4月3日星期二
编码意义-扫盲班1期
1. 常见编码内容--英文 DOS编码:
00000000 ff ff ff ff ff ff 00 60 6e 47 92 b5 08 06 00 01 'nG庹..
00000010 08 00 06 04 00 01 00 60 6e 47 92 b5 a9 fe 00 7d ........'nG庹... .}
00000020 00 00 00 00 00 ..........................
2. 字节值:
0x00 空字节
0x01
0xDD
3. 内存地址:
0x0000 ~ 0xFFFF
0x06EA1000
0x6EA3050
【for instance】
Q&A:
a:0x7c882f9c错误是什么意思?
b:内存中的这一地址出了问题,至于是什么导致的可能性则有很多咯。诸如:对于采用动态分配的应用程序,由于自身bug引用了不正常的内存指针,出现:程序试图读写一块“应该可用”的内存,但不知为什么,这个预料中可用的指针已经失效了;劣质的内存条;微软WINDOWS系统的漏洞,windows把内存地址0X00000000到0X0000ffff指定为分配null指针的地址范围,如果程序试图访问这一地址,则认为是错误,等等等等。
00000000 ff ff ff ff ff ff 00 60 6e 47 92 b5 08 06 00 01 'nG庹..
00000010 08 00 06 04 00 01 00 60 6e 47 92 b5 a9 fe 00 7d ........'nG庹... .}
00000020 00 00 00 00 00 ..........................
2. 字节值:
0x00 空字节
0x01
0xDD
3. 内存地址:
0x0000 ~ 0xFFFF
0x06EA1000
0x6EA3050
【for instance】
Q&A:
a:0x7c882f9c错误是什么意思?
b:内存中的这一地址出了问题,至于是什么导致的可能性则有很多咯。诸如:对于采用动态分配的应用程序,由于自身bug引用了不正常的内存指针,出现:程序试图读写一块“应该可用”的内存,但不知为什么,这个预料中可用的指针已经失效了;劣质的内存条;微软WINDOWS系统的漏洞,windows把内存地址0X00000000到0X0000ffff指定为分配null指针的地址范围,如果程序试图访问这一地址,则认为是错误,等等等等。
残酷而现实的历史观
或许人类的战争是有道理的。或许外向性的政权是必然的。
15世纪以来长达400年内向性的、异常稳定的中国带来了异族的欺凌。西方世界外向性的思想、迅速地交流、物质和资金的匮乏、社会的不稳定才间接带来了思想、经济形态、军事技术的飞跃进步。
只要人类不灭亡,或许由于人类不断相互攻伐带来不断的军事技术革命会在多少万年以后成为我们抵御外星异种入侵的有效手段。
毕竟,我们在任意大的“小”环境中不管有多宁静和谐却都不可避免要面对所谓“小”环境之外的残酷挑战。因为资源有限,而基因却渴求尽可能地大量繁殖保持物种延续。所以物竞天择、适者生存是我们宇宙一个亘古不变的道理。所以在必然的潜在挑战不断的宇宙中,保持宁静和谐最终将降低竞争能力最终败于某个国家、某个物种、某个异形。
当然,全球史在统一,人类内部应该提高聚合力(团结),不要因为不可控制的竞争将我们引向灭亡。
15世纪以来长达400年内向性的、异常稳定的中国带来了异族的欺凌。西方世界外向性的思想、迅速地交流、物质和资金的匮乏、社会的不稳定才间接带来了思想、经济形态、军事技术的飞跃进步。
只要人类不灭亡,或许由于人类不断相互攻伐带来不断的军事技术革命会在多少万年以后成为我们抵御外星异种入侵的有效手段。
毕竟,我们在任意大的“小”环境中不管有多宁静和谐却都不可避免要面对所谓“小”环境之外的残酷挑战。因为资源有限,而基因却渴求尽可能地大量繁殖保持物种延续。所以物竞天择、适者生存是我们宇宙一个亘古不变的道理。所以在必然的潜在挑战不断的宇宙中,保持宁静和谐最终将降低竞争能力最终败于某个国家、某个物种、某个异形。
当然,全球史在统一,人类内部应该提高聚合力(团结),不要因为不可控制的竞争将我们引向灭亡。
2007年4月1日星期日
庆祝google博客解封
这些天一直通过添加域名-ip对应列表的方式手工实现访问blogspot,所以没有察觉是什么时候解封的,总之昨天还不稳定,有时候仍然无法登录。今天终于好了,庆祝下---把命运交给别人就是这样,我宁可google博客提供vip服务,单独划出来一个区域,每年收取少量的费用来保证其稳定性和大陆可访问性。
希望这次解封不是偶然现象。所有博客中我最喜欢google博客了,她界面简约清新,很少有bug。本来还喜欢bokee网,但是它却离这个方向渐行渐远,哎。
希望这次解封不是偶然现象。所有博客中我最喜欢google博客了,她界面简约清新,很少有bug。本来还喜欢bokee网,但是它却离这个方向渐行渐远,哎。
订阅:
博文 (Atom)