Posted by Ryan on 2011/03/23
刷新和输入网址后回车的区别
- 强制刷新(ctrl+F5):不理会缓存协商,全部重新获取.此时请求中的Cache-Control值为no-cache
- 刷新(F5)时:当点击浏览器上的刷新,客户端发送的请求中的Cache-Control均是max-age=0,表示validate操作,发送请求到服务器要求检查cache,再更新cache,一般得到的是304 Not Modified,表示没变动
- 输入网址直接回车时:如果Expired或Cache-Control还未过期,则不会返回304状态,因为浏览器已经不用向web服务器发出请求
Expires与Cache-Control的区别
- 给静态资源(HTML文件,图片文件等)加上Expires/Cache-Control Header。如果HTTP Response中有Expires这样的Header的话,浏览器会Cache这个资源,理想状况下(注意,只是理想状况),在Expire Date之前,不会再发HTTP请求给Server要这个资源,不过Expires的值只能是一个固定日期,比如“Thu 27 Nov 2008 07:00:00 GMT”,不能是一个类似“从现在开始之后10年”这样一个随机浮动的值,如果要这样的效果,可以用Cache-Control这样的Header,如果HTTP Resposne中有这样的Header:“Cache-Control: max-age = 100”,表示这个资源在cache中的最大寿命是100秒。
- 同一个HTTP Response中可以同时有Expires和Cache-Control,但是Cache-Control权限比Expires大,会override它的。
- HTTP/1.0有一个功能比较弱的缓存控制机制:Pragma,使用HTTP/1.0的缓存将忽略Expires和Cache-Control头。
Last-modified/If-Modified-Since与Etag/If-None-Match区别
- HTTP的Response中还会有另外一个Header叫Last-Modified,比如“Last-Modified: Thu, 06 Apr 2006 21:17:12 GMT”,浏览器访问一个URI得到这样的Resposne之后,就知道这个资源最后一次的修改时间,下次需要再次获得这个资源的时候,会发一个Request给Server,不过这个Request中有一条“If-Unmodified-Since: Thu, 06 Apr 2006 21:17:12 GMT”,如果在Server端在这个日期之后对这个资源进行了修改,就会照常返回这个资源给Client端,但是如果没有修改,就会返回一个304 (Not Modified) Response而不返回资源,告诉Client端:“这个资源从上次给你之来从来没改过,你放心用你Cache中的好了。” 一个304 Response比一个静态资源通常小多了,这样就节省了网络带宽。
- 除了Last-Modified,HTTP Response中还可能有另外一个Header: ETag。在多台负载均衡的服务器环境下,同一个文件可能会有不同的etag或者文件修改日期,浏览器每次都会重新下载,这点要根据实际情况考虑设置。
- 比较一下Expires和Last-Modified这两个东西,似乎Last-Modified比不上Expires,因为虽然它能够节省一点带宽,但是还是逃不掉发一个HTTP请求出去,而Expires却使得浏览器干脆连HTTP请求都不用发。不过当用户在IE或者Firefox里面按F5或者点击Refresh按钮的时候(不是在URL栏里重新输入一遍URL然后回车),就算对于有Expires的URI,一样也会发一个HTTP请求出去,所以,Last-Modified还是要用的(返回304),而且要和Expires一起用。
Apache配置
- 在expires.conf设置expires,加了expires后,Cache-Control也会有相应换算后的值
<IfModule mod_expires.c>
ExpiresActive On
ExpiresByType image/gif "access plus 1 hour"
ExpiresByType image/jpeg "access plus 2 hour"
</IfModule>
对于一般的纯静态页面,如html、gif、jpg、css、js,默认安装的Apache服务器,不会在响应头添加这个字段。
- Firefox浏览器接受到相应请求后,如果发现没有Expires字段,浏览器根据文件的类型和“Last-Modified”字段来推断出一个合适的失效时间,并存储在客户端(Firefox的缓存),推测出的时间一般是接受到响应时间后的三天左右,以后的请求就可以根据Firefox的缓存过期时间(而非http指定)来决定是否使用客户端缓存。
- Apache服务器默认情况下,会对所有的静态、动态文件的响应头添加ETag字段。如果要关闭ETag,对于Apache,在httpd.conf或者.htaccess中加一行就搞定了:FileETag none
- 无论是纯静态页面还是动态页面,Firefox浏览器巧妙地按照接受到服务器响应的时间设置缓存页面的Last-Modified(Firefox的缓存),而不是按照http响应头部中的Last-Modified字段。
- 一般纯静态页面本身都会有Last-Modified信息,Apache服务器会读取页面文件中的Last-Modified信息,并添加到http响应头部。
-
对于动态页面,如果在页面内部没有通过函数强制加上Expires,例如header(”Expires:”。 gmdate(”D, d M Y H:i:s”) 。 ”GMT”),Apache服务器会把Wed, 11 Jan 1984 05:00:00 GMT作为Expires字段内容,返回给浏览器。
- 对于动态页面,如果在页面内部没有通过函数强制加上Last-Modified,例如header(”Last-Modified: ” 。 gmdate(”D, d M Y H:i:s”) 。 ”GMT”),Apache服务器会把当前时间作为Last-Modified,返回给浏览器。
- 关闭Last-modified
LoadModule headers_module modules/mod_headers.so
<FilesMatch "\.(gif|jpg|png)">
Header unset Last-Modified
</FilesMatch>
- 开启gzip
<ifmodule mod_deflate.c>
DeflateCompressionLevel 9
AddOutputFilterByType DEFLATE text/html text/plain text/xml application/x-httpd-php
AddOutputFilter DEFLATE js css
</ifmodule>
Posted by Ryan on 2010/09/02
使用了一段时间的vim后,感觉越用越好用,它的操作完全颠覆了以往编辑文本的习惯,编辑文本不再枯燥,完全成了一种享受。尤其是它的可定制性真让人欲罢不能,下面我把自己目前用的.vimrc配置文件与大家分享,因为用Vim没多久,这份配置还有很多不足之处,但我还是希望大家能从中获益,做一个快乐的vimmer! 如有其它好的配置,还请不吝赐教 :)
"关闭与vi的兼容模式
set nocp "nocompatible
"搜索结果高亮
set hls "hlsearch
"增量搜索
set is "incsearch
"显示行号
set nu "number
"退格删除indent,eol,start
set backspace=indent,eol,start
"按h,l时,如果到头,则跳到上一行或下一行
set whichwrap=h,l
"关闭备份
set nobackup
"高亮显示光标所在行
set cursorline
"禁用鼠标点击时的虚拟选中模式
set mouse-=a
"tab键对应的字符宽度
set tabstop=4 "ts
"自动缩进时的字符宽度
set shiftwidth=4 "sw
"自动将Tab转化为对应宽度的空格
set et "noexpandtab
"当使用et将Tab替换为空格之后,不用按Backspace多次, 按一下即可
set smarttab
"自动缩进
set autoindent
"防止特殊符号无法正常显示。 在 Unicode 中, 许多来自不同语言的字符, 如果字型足够近似的话, 会把它们放在同一个编码中。 但在不同编码中, 字符的宽度是不一样的。
set ambiwidth=double
"自动切换当前目录
set autochdir
"设置当前字符编码为 UTF-8
set encoding=utf-8
"设置菜单语言和编码
set langmenu=zh_CN.UTF-8
"设置提示信息的语言和编码
language messages zh_CN.utf-8
"设置编码的自动识别
set fileencodings=utf-8,gbk,chinese,latin-1
"语法高亮
syntax on
"开启文件类型自动识别, 启用文件类型插件, 启用针对文件类型的自动缩进
filetype plugin indent on
"设置tag list插件
let Tlist_Ctags_Cmd="E:/Vim/vim72/ctags.exe"
let Tlist_Use_Right_Window=1
let Tlist_Auto_Open=0
"关闭菜单和工具栏,以最大化可视范围
set guioptions-=m
set guioptions-=T
"使用主题
colorscheme lucius
"键绑定
map <F3> gg=G``
map <F4> ggvGy``
map <C-F5> "+y
map <C-F6> "+p
Posted by Ryan on 2010/08/24
最近有人问我一个问题:String是什么?
是什么?脑子一片混乱。不可变?不是基本数据类型但又像基本数据类型?顿时很多模糊的理解涌入脑海,怎么都理不清,究其原因,还是对String在JVM里的实现原理不甚理解。为了彻底搞清究竟什么是String,今天特意看了很多相关的资料,终于有所感悟,感悟之余,记录于此,与大家共享。(部分内容抄摘自网上)
一、创建String
创建一个String对象,主要有两种方式:
- String s=”Hello world!”;
- String s=new String(“Hello world”);
两种方式虽然都实现了创建一个String对象的功能,但实现的原理却大不相同。在讨论这两种方法的不同之前,我们先来了解一下JVM里的常量池概念,对接下来的理解很有帮助。
相信大家都知道,Java程序在运行之前,编译器首先要把源代码编译成字节码文件(.class文件),然后JVM再解释执行.class文件。其中,在.class文件中有一个非常重要的项—常量池,我们上面代码中的”Hello world”字符串被编译之后,就被存放在class常量池中的字符串常量表中。改用网上一段话:
在Java源代码中的每一个字面值字符串,都会在编译成class文件阶段,形成标志号 为8(CONSTANT_String_info)的常量表 。 当JVM加载 class文件的时候,会为对应的常量池建立一个内存数据结构,并存放在方法区中。同时JVM会自动为CONSTANT_String_info常量表中 的字符串常量字面值 在堆中创建 新的String对象(intern字符串对象)。然后把CONSTANT_String_info常量表的入口地址转变成这个堆中String对象的直接地址(常量池解析)。
源代码中所有相同字面值的字符串常量只可能建立唯一一个intern字符串对象。另外,我们也可以调用String的intern()方法来使得一个常规字符串对象成为intern字符串对象。
好了,下面我们来讨论一下第一种方法,也是大家非常常用的方法:
String s=”Hello world!”
首先在编译期,也就是在运行这段指令之前,JVM就已经为”Hello world”在堆中创建了一个intern字符串,局部变量s存储的是早已创建好的intern字符串的堆地址。也就是说,不管有几条String s1=”Hello world”,堆中都只有1个值为”Hello world”的字符串。
那么第二种方法呢?
String s=new String(“Hello world”)
同样在编译期,JVM也为”Hello world”在堆中创建了一个intern字符串,然后用这个intern字符串的值来初始化new出来的新String对象,局部变量s实际上存储的是new出来的堆对象地址。 此时在JVM管理的堆中,有两个相同字符串值的String对象:一个是intern字符串对象,一个是new新建的字符串对象。
最后,来段代码做个更形象的比较:
//代码1
String sa = "ab";
String sb = "cd";
String sab=sa+sb;
String s="abcd";
System.out.println(sab==s); // false
//代码2
String sc="ab"+"cd";
String sd="abcd";
System.out.println(sc==sd); //true
代码1中局部变量sa,sb存储的是堆中两个intern字符串对象的地址。而当执行sa+sb时,JVM首先会在堆中创建一个StringBuilder类,同时用sa指向的intern字符串对象完成初始化,然后调用append方法完成对sb所指向的intern字符串的合并操作,接着调用StringBuilder的toString()方法在堆中创建一个String对象,最后将刚生成的String对象的堆地址存放在局部变量sab中。而局部变量s存储的是常量池中”abcd”所对应的intern字符串对象的地址。 sab与s地址当然不一样了。这里要注意了,代码1的堆中实际上有五个字符串对象:三个intern字符串对象、一个String对象和一个StringBuilder对象。
代码2中”ab”+”cd”会直接在编译期就合并成常量”abcd”, 因此相同字面值常量”abcd”所对应的是同一个拘留字符串对象,自然地址也就相同。
二、String,StringBuffer和StringBuilder
- 通过查看源码可以发现,String中的value[]是常量(final)数组,只能被赋值一次;而StringBuffer中的value[]就是一个很普通的数组,而且可以通过append()方法将新字符串加入value[]末尾。
- StringBuffer和StringBuilder的区别是StringBuffer是线程安全的,而后者不是。这是因为在源代码中StringBuffer的很多方法都被关键字synchronized 修饰了,而StringBuilder没有。另外,由于String是不可变的,也就是只读,自然也是安全的了。
- 因为String对象中的value[]是不能改变的,每一次合并后字符串值都需要创建一个新的String对象来存放。循环1000次自然需要创建1000个String对象和1000个StringBuilder对象,效率低就可想而知了;而StringBuffer/StringBuilder,只需要将自己的value[]数组不停的扩大来存放即可,循环过程中无需在堆中创建任何新的对象,效率自然就高了。
三、总结:
- 不停的创建对象是程序低效的一个重要原因。那么相同的字符串值能否在堆中只创建一个String对象?可以!除了程序中的字符串常量会被JVM自动创建拘留字符串之外,调用String的intern()方法也能做到这一点。当调用intern()时,如果常量池中已经有了当前String的值,那么返回这个常量指向intern对象的地址。如果没有,则将String值加入常量池中,并创建一个新的intern字符串对象。
- String的种种行为都来源于它的immutable性. 因为它是不变的,没有线程安全问题,可以无限共享,池化当然最节省时间空间; 也因为它是不变的,用”+”导致N多的新对象生成,才生的效率问题.
四、知识补充:
equals 和 == 的区别
- equals 方法(是String类从它的超类Object中继承的)被用来检测两个对象是否相等,即两个对象的内容是否相等。
- ==用于比较引用和比较基本数据类型时具有不同的功能:比较基本数据类型,如果两个值相同,则结果为true ; 在比较引用时,如果引用指向内存中的同一对象,结果为true
堆、栈与常量池:
- 栈:存放基本类型的变量数据和对象的引用,但对象本身不存放在栈中,而是存放在堆(new 出来的对象)或者常量池中(字符串常量对象存放在常量池中。)
- 堆:存放所有new出来的对象。
- 静态域:存放静态成员(static定义的)
- 常量池:存放字符串常量和基本类型常量(public static final)。
栈和常量池中的对象可以共享,堆中的对象不可以共享。栈中的数据大小和生命周期是可以确定的,当没有引用指向数据时,这个数据就会消失。堆中的对象的由垃圾回收器负责回收,因此大小和生命周期不需要确定,具有很大的灵活性。
字符串:其对象的引用都是存储在栈中的,如果是编译期已经创建好(直接用双引号定义的)的就存储在常量池中,如果是运行期(new出来的)才能确定的就存储在堆中。对于equals相等的字符串,在常量池中永远只有一份,在堆中有多份。
Posted by Ryan on 2010/08/17
今天晚上估计要在公司待的很晚了,趁着一些任务在自动运行的间隙,抽空整理一下自己喜欢的一些eclipse插件:
这次就先介绍这几个了,以后有发现更好的,我会及时与大家分享的。
Posted by Ryan on 2010/05/09
前几天由于自己的不小心,把跟了自己多年的台式机的主板给弄坏了,本来想去保修的,结果看了一下标签,保修期居然刚过了2个月,杯具啊…
其实早就想买本本了,只不过对那台式机有深厚的感情,而且一直工作地非常稳定,也不忍心将它打入冷宫.这一次虽然它受伤了,但我还是会把它救回来的,只不过接下来它要退居二线了.
小Y!一次不经意地懈逅,让我深深地爱上了它.它那时尚的外表,再加上强劲的配置,真让人欲罢不能.虽然它侧边那条橙色的条纹让我有点别扭,但瑕不掩瑜,仍然非常值得拥有.
昨天,y460被我收入囊中…特写篇博文记念一下:)

买来后,迫不及待试了一下它的卖点之一:JBL专业音响.果然名不虚传,比我那个创新的2.1还要好,音质清晰浑厚.大喜之外,还体验了一下许多酷酷的功能:slidebar的拉链式的锁屏效果与win7的aero效果相得益彰;双显卡一键切换的功能让我在性能和节能上能自由选择….太多太多了,更多的功能还要在以后慢慢发掘.
其实买本本最主要的目的还是为了方便工作,由于今后的工作平台更多的会在linux下,于是,在体验了y460的几个主要功能后,我开始装上了久闻大名的lucid lynx(ubuntu 10.04 LTS),这只清醒的猞猁作为LTS版本,其重要性可见一斑.一改之前的土黄色,这一次用上了更为悦目清新的紫色,其特效丝毫不逊色于win7.而且与社区的结合非常紧密,像Twitter和Facebook都无缝地整合在里面,不过由于国情,这些功能就有点打折扣了.由于本篇博文是为了记念本本的到来,ubuntu的功能我就不详细介绍了。
我相信我会充分利用好如此优秀的装备,开启事业的新篇章,迎接更美好的未来。