JFIF/JPEG文件格式

JFIF文件格式即JPEG文件交换格式(JPEG File Interchonge Format)。
一般的JFIF文件由下面的9个部分组成:
(字段偏移量 字段长度(若未说明“长度不定”则表明在任何情况下长度均为所写的值) 字段内容(若未说明“内容不定”则在任何情况下内容均为所写的值,为方便表示还可以把内容设为某值))
注意:从文件的0x0c偏移处开始才是真正的缩略图文件,前面的3个Long类型的结构是对图形在索引文件中的一个描述。
(1) 图像开始SOI(Start of Image)标记
       0h 2字节 0xFFD8
(2) APP0标记(Marker)
       0h 2字节 0xFFE0
   ① APP0长度(length)(①~⑨九个字段的总长度)
       2h 2字节 内容不定(①~⑨九个字段的总长度)  
   ② 标识符(identifier)
       4h 5字节 0x4A46494600 即“JFIF0”
   ③ 版本号(version)
       9h 2字节 0x0102 JFIF的版本号目前基本上都是1.2  
   ④ X和Y的密度单位(units=0:无单位;units=1:点数/英寸;units=2:点数/厘米)
       bh 1字节 只有0,1,2三个值可选,其分别代表的意义如上
   ⑤ X方向像素密度(X density)
       ch 2字节 取值范围未知
   ⑥ Y方向像素密度(Y density)
       eh 2字节 取值范围未知  
   ⑦ 缩略图水平像素数目(thumbnail horizontal pixels)
       10h 1字节 取值范围未知
   ⑧ 缩略图垂直像素数目(thumbnail vertical pixels)
       11h 1字节 取值范围未知
   ⑨ 缩略图RGB位图(thumbnail RGB bitmap)
       12h 长度可能是3的倍数 内容不定
           本段(APP0)可以包含图像的一个微缩版本,存为24位的RGB像素。如果没有微缩图像
       (这种情况更常见),则⑦“缩略图水平像素数目”和⑧“缩略图垂直像素数目”的值均为0。
(3) APPn标记(Markers),其中n=1~15(任选)
   ① APPn长度(length)(①②两个字段的总长度)
   ② 详细信息(application specific information)
         对每个APP:
         若为APPN(N=1~F(以16进制表示,N任选其中一个))
         标记
             mh 2字节 0xFFEN
         长度
             (m+2)h 2字节 内容不定(设为n(10进制))(本字段与下一字段的总长度)
         详细信息
             (m+4)h n-2字节(即长度减2) 内容不定
(4) 一个或者多个量化表DQT(Difine Quantization Table)
       0h 2字节 0xFFDB
   ① 量化表长度(quantization table length)(①~②两个字段的总长度)
       2h 2字节 内容不定(①~②两个字段的总长度)  
   ② 量化表(quantization table)
         a) P/T(高四位:精度,低四位:表ID)
         b) 表项
           对每个量化表:
           P/T(高四位:精度,低四位:表ID)
               mh 1字节 精度, 0 表示 8 bit, 1表示 16 bit;ID取值范围为0~3, 否则错误          
           表项
               (m+1)h (64×(精度+1))字节 内容长,故略
(5) 帧图像开始SOF0(Start of Frame)
       0h 2字节 0xFFC0
   ① 帧开始长度(start of frame length) (①~⑥六个字段的总长度)
           2h 2字节 内容不定(①~⑥六个字段的总长度)
   ② 精度(precision),每个颜色分量每个像素的位数(bits per pixel per color component)
           4h 1字节 每个样本位数, 通常是 8 (大多数软件不支持 12 和 16)
   ③ 图像高度(image height)
           5h 2字节 内容不定(如果不支持 DNL 就必须 >0)
   ④ 图像宽度(image width)
           7h 2字节 内容不定(如果不支持 DNL 就必须 >0)
   ⑤ 颜色分量数(number of color components)
           9h 1字节 内容不定(灰度图是 1, YCbCr/YIQ 彩色图是 3, CMYK 彩色图是 4,我们
               这里讨论的JFIF使用的是YCbCr,故这里颜色分量数为3)
   ⑥ 对每个颜色分量(for each component)
         a) ID
         b) 垂直方向的样本因子(vertical sample factor)
         c) 水平方向的样本因子(horizontal sample factor) (b) c)共占用1字节,b)占用低4
             位,c)占用高4位)
         d) 量化表号(quantization table#)
                 JFIF格式使用的是YCbCr所以有3个分量(这里特别要注意的是颜色分量的ID号是有
           含义的,1代表Y,2代表Cb,3代表Cr,4代表I,5代表Q):
               1) ID
                     ah 1字节 0x01
                 (高四位)水平(低四位)垂直样本因子
                     bh 共1字节 0x22
                   量化表号
                     ch 1字节 内容不定(本分量使用的量化表的ID号)
               2) ID
                     dh 1字节 0x02
                 (高四位)水平(低四位)垂直样本因子
                     eh 共1字节 0x11
                   量化表号
                     fh 1字节 内容不定(本分量使用的量化表的ID号)
               3) ID
                     10h 1字节 0x03
                 (高四位)水平(低四位)垂直样本因子
                     11h 共1字节 0x11
                   量化表号
                     12h 1字节 内容不定(本分量使用的量化表的ID号)
(6) 一个或者多个霍夫曼表DHT(Difine Huffman Table)
       0h 2字节 0xFFC4
     ① 霍夫曼表的长度(Huffman table length) (①~②两个字段的总长度)
         2h 2字节 内容不定(①~②两个字段的总长度)
     ② 对每个霍夫曼表(一般情况下,霍夫曼表不止一个,但是绝对不多于4个)
         a) 表号
         b) 类型:AC或者DC(Type, AC or DC。其中0为DC表,1为AC表)(a) b)共占用1字
           节,a)占用低4位,b)占用高4位)
         c) 长16个字节的编码,其代码代数和为接下来的编码的长度
         d) 内容编码
               对每个霍夫曼表:
             (高四位)类型和(低四位)表号
                   mh 共1字节 内容不定(有四个可能:0x00表示第0个DC表,0x01表示第1
                         个DC表,0x10表示第0个AC表,0x11表示第1个AC表)
               长16个字节的编码
                   (m+1)h 16字节 内容不定(设这16个字节上数据之和为n)
               内容编码
                   (m+17)h n字节 内容长,故略
(7) 定义重新开始间隔DRI(Difine Restart Interval)(在没有DRI标记,或间隔为零时,就不存在重
       开始间隔和重开始标记)
       0h 2字节 0xFFDD
   ① 长度
       2h 2字节 0x0004(①~②两个字段的总长度)
   ② MCU 块的单元中的重新开始间隔
       4h 2字节 内容不定(设为n,则意思是说,每n个MCU块就有一个RSTn标记。第一个标记
             是RST0,然后是RST1等,RST7后再从RST0重复)
(8) 扫描开始SOS(Start of Scan)
         0h 2字节 0xFFDA
   ① 扫描开始长度(start of scan length)
         2h 2字节 内容不定(①~③再加上④的a) b) c)的总长度)
   ② 颜色分量数(number of color components)
         4h 1字节 应该和⑸⑤的值相同(灰度图是1, YCbCr/YIQ 彩色图是3, CMYK 彩色图是4)
   ③ 每个颜色分量
         a) ID
         b) 交流系数表号(AC table #)
         c) 直流系数表号(DC table #)(b) c)共占用1字节,b)占用低4位,c)占用高4位)
             由②得到这里的颜色分量数为3(这里的颜色分量的ID号的含义和⑸⑥的一样,1代表
         Y,2代表Cb,3代表Cr,4代表I,5代表Q):
               1) ID
                     5h 1字节 0x01
                 (高四位)直流(低四位)交流数表号
                     6h 共1字节 0x00
               2) ID
                     7h 1字节 0x02
                 (高四位)直流(低四位)交流数表号
                     8h 共1字节 0x11
               3) ID
                     9h 1字节 0x03
                 (高四位)直流(低四位)交流数表号
                     ah 共1字节 0x11
   ④ 压缩图像数据(compressed image data)
         a) 谱选择开始
             bh 1字节 0x00
         b) 谱选择结束
             ch 1字节 0x3F
         c) 两个4位字段,高位和低位的谱选择
             dh 1字节 在基本JPEG中总为00
         d) 数据
             eh 长度不定 内容长,故略
(9) 图像结束EOI(End of Image)
         0h 2字节 0xFFD9

java.util.Arrays的排序分享

java.uti.Arrays 包含用来操作数组(比如排序和搜索)的各种方法。这篇文章我们就来研究一些大师们写的排序算法。

(1) 基本数据类型数组的排序,如Arrays.sort(int[])等。采用了一种经过调优的快速排序。该算法改编自 Jon L. Bentley 和 M. Douglas McIlroy 合著的 Engineering a Sort Function", Software-Practice and Experience Vol. 23(11) P. 1249-1265 (November 1993)。此算法在许多数据集上提供 n*log(n) 性能,这导致其他快速排序会降低二次型性能。
下面是JDK中调优快速排序算法的源代码:

   /**
     * 将指定范围的整形数组升序排序。
     * x[] 待排数组
     * off 从数组的第off个元素开始排序
     * len 数组长度
     */
    private static void sort1(int x[], int off, int len) {
 //优化1:在小规模(size<7)数组中,直接插入排序的效率要比快速排序高。
 if (len < 7) {
     for (int i=off; i<len+off; i++)
      for (int j=i; j>off && x[j-1]>x[j]; j--)
       swap(x, j, j-1);
     return;
 }

 //优化2:精心选择划分元素,即枢轴
 //如果是小规模数组(size<=7),直接取中间元素作为枢轴
 //如果是中等规模数组(7=<size<=40),则在数组首、中、尾三个位置上的数中取中间大小的数作为枢轴
 //如果是大规模数组(size>40),则在9个指定的数中取一个伪中数(中间大小的数s)
 int m = off + (len >> 1);
 if (len > 7) {
     int l = off;
     int n = off + len - 1;
     if (len > 40) {       
   int s = len/8;
   l = med3(x, l, l+s, l+2*s);
   m = med3(x, m-s,   m,   m+s);
   n = med3(x, n-2*s, n-s, n);
     }
     m = med3(x, l, m, n);
 }
 int v = x[m];

         //优化3:每一次枢轴v的划分,都会形成形成一个形如  (<v)* v* (>v)*
        //阶段一,形成 v* (<v)* (>v)* v* 的数组
        int a = off, b = a, c = off + len - 1, d = c;
        while(true) {
     while (b <= c && x[b] <= v) {
   if (x[b] == v)
       swap(x, a++, b);
   b++;
     }
     while (c >= b && x[c] >= v) {
   if (x[c] == v)
       swap(x, c, d--);
   c--;
     }
     if (b > c)
      break;
     swap(x, b++, c--);
 }

 //阶段二,将枢轴和与枢轴相等的元素交换到数组中间
 int s, n = off + len;
 s = Math.min(a-off, b-a  );  vecswap(x, off, b-s, s);
 s = Math.min(d-c,   n-d-1);  vecswap(x, b,   n-s, s);

 //阶段三,递归排序与枢轴不相等都元素区间
 if ((s = b-a) > 1)
     sort1(x, off, s);
 if ((s = d-c) > 1)
     sort1(x, n-s, s);
    }


★ 优化1:在小规模(size<7)数组中,直接插入排序的效率要比快速排序高。

      没有一种排序在任何情况下都是最优的《基于比较的内部排序总结 》。 O(N^2)级别的排序看起来似乎比所有先进排序要差的多。但实际上也并非如此,Arrays中的sort()算法就给了我们一个很好的例子。当待排数组规模非常小的时候(JDK中规模的阈值为INSERTIONSORT_THRESHOLD=7),直接插入排序反而要比快排,归并排序要好。

    这个道理很简单。数组规模小,简单算法的比较次数不会比先进算法多多少。相反,诸如快排,归并排序等先进算法使用递归操作,所付出的运行代价更高。

阅读剩余部分...

win7下ps/2键盘、笔记本键盘和触摸板无法使用的解决办法

    今天笔记本刚开机,键盘就没反应了,打开设备管理器一看,PS/2键盘和触摸板设备前面就有个黄色的小图标,说注册表损坏,无法使用。赶紧用U盘的驱动精灵装上,但驱动精灵检测不到任何问题,也就无法修复了。还好,鼠标还可以用,搜狗输入法的手写输入法此时也帮上我的忙了。总算找到问题原因了,我差点要重装系统,还好我记住了,冲动是魔鬼。很多电脑故障问题要解决起来很简单的,完全没必要重装系统。
   解决方法很简单。
1.定位到HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\Class \{4D36E96B-E325-11CE-BFC1-08002BE10318}
2.修改UpperFilters项的内容为kbdclass
3.卸载键盘设备,重新启动。

问题解决。反思了下,是昨天玩CF玩不起,我卸载后,安装了最新的腾讯的CF游戏给造成的,,我玩的时候CF还老给我强制退出,说我系统有安全问题,简直瞎扯!后来在网上也看到类似的,也是被腾讯坑害的人。http://community.chinahrd.net/home.php?mod=space&uid=599569&do=blog&id=177323
好吧,狗日的腾讯。

转:hotspot内部对synchronize的实现

背景:
Java语言相较于c,c++的一个优势,是其从语言层面就提供了对多线程同步以及相互协作的支持;而不像c,c++,要通过其他的库才能写多线程程序。在Java语言里,通过synchronize关键字来同步一段关键代码片断(critical area),而通过wait,notify来实现线程间相互协作。本文主要描述一下sun的hotspot是如何来支持synchronize及wait和notify的。

在hotspot的实现里,每个java对象有一个对应的c++对象,每个用来表达java对象的c++对象都有一个header,占用2个word,第一个word成为mark word,第二个word则用来指向一个klass,该klass用来表征该对象的类型信息。第一个mark word,在某些情况下会用来表示同步信息,所以需要我们重点探究一下。


mark word是用来表征对象一些信息的对象头,目前依据jvm是32位还是64位,而分为32位64位2种形式。由于2者差别不大,所以我们这里以32位为例子,来讲解一下mark word。
在32位jvm上,markword为32位长,根据具体各个bit的数值的不同,可以组合成4种大类(表明该头markword所在的对象当前的状态),具体如下图所示。

我们现在需要关注的是前2类,即当markword表示该对象一个普通java对象或者被biased locking的对象。

2.hotspot当前对synchronize的实现类型及其应用场景
当前的hotspot共有3种类型的锁,来实现synchronize的语义,之所以有3种,是因为这3种要解决的问题不同,所做的优化也不同。这3种锁分别为biased locking,stack lock,infalted(ObjectMonitor).简单除暴的来讲,从轻量级上来说,biased lock最优,inflated 最差。

为了便于大家的认知,先从优化做的最少的Infalte锁开始讲起。

阅读剩余部分...

转:非主流并发工具之 ForkJoinPool

ForkJoinPool 是 Java SE 7 新功能“分叉/结合框架”的核心类,现在可能乏人问津,但我觉得它迟早会成为主流。分叉/结合框架是一个比较特殊的线程池框架,专用于需要将一个任务不断分解成子任务(分叉),再不断进行汇总得到最终结果(结合)的计算过程。比起传统的线程池类 ThreadPoolExecutorForkJoinPool 实现了工作窃取算法,使得空闲线程能够主动分担从别的线程分解出来的子任务,从而让所有的线程都尽可能处于饱满的工作状态,提高执行效率。

ForkJoinPool 提供了三类方法来调度子任务:

execute 系列
异步执行指定的任务。
invokeinvokeAll
执行指定的任务,等待完成,返回结果。
submit 系列
异步执行指定的任务并立即返回一个 Future 对象。

子任务由 ForkJoinTask 的实例来代表。它是一个抽象类,JDK 为我们提供了两个实现:RecursiveTaskRecursiveAction,分别用于需要和不需要返回计算结果的子任务。ForkJoinTask 提供了三个静态的 invokeAll 方法来调度子任务,注意只能在 ForkJoinPool 执行计算的过程中调用它们。

ForkJoinPoolForkJoinTask 还提供了很多让人眼花缭乱的公共方法,其实它们大多数都是其内部实现去调用的,对于应用开发人员来说意义不大。

下面以统计 D 盘某文件夹文件个数为例。这实际上是对一个文件树的遍历,我们需要递归地统计每个目录下的文件数量,最后汇总,非常适合用分叉/结合框架来处理:

   让人围观的是,这并不比单线程的Files.walkFileTree(...)
refer:http://www.blogjava.net/shinzey/archive/2012/02/09/368312.html

流程图绘制软件介绍

    因为工作中经常需要用到流程图软件,上网仔细挑选了几款相对比较优秀的软件,一一介绍。
注意:流程图也叫Flowchart,不是思维导图Mind Map。不过有的软件既能绘制Mind Map,也能绘制Flowchart,如Edraw Mind Map(也称亿图图示专家),不过亿图如今有了专门的Flowchart了。

1.Diagram Designer


免费软件,windows平台,最新版本 1.25.下载地址:http://meesoft.logicnet.dk/
Diagram designer
安装包体积:1.3M
可以画一些简单的流程图,GUI示意图(Diagram Designer的特色就在这里),主要的图元有:简单图形,流程图,GUI窗口和元素,UML类图。
优点和特色:体积小,可画GUI示意图,展示窗口,表格等。
缺点:图元样式不够丰富,太少了。属性和文本编译不够直观,另外导出的图像质量不是很好,特别是曲线图形锯齿比较明显。导出时,不会智能的选择指导出可见部分。因此使用前需要预先设置好画布大小。
输出效果:diagram Designer.png

2.Dia


免费软件,跨平台,最新版本0.97.2,下载地址:http://projects.gnome.org/dia/
WINDOWS安装包 19M.由于dia最初是linux平台下的软件,所以发扬了linux桌面软件bug比较多,用户不友好,难适应的传统。

阅读剩余部分...

SPDY 协议介绍

目前支持SPDY协议的应用有:firefox开发板,jetty8等。
SPDY 目前是一种应用层实验性协议,旨在让互联网访问更快速,减少web页面的延迟。

SPDY 设计特点

协议在SSL层的基础上,增加了一个session 层,从而在一个tcp 连接基础上,实现了多并发和交叉流传输

HTTP 的GET ,POST 仍旧采用旧有的消息格式,当然SPDY 协议对原有的数据做了封装和编码,这里采用Wrapper设计模式。
spdy.png

流是双向的,比如,既可以从客户端发起,也可以从服务器端发起(PUSH)

SDPY的目标就是通过其基本特性和高级特性,来达到低访问延迟

基本特性包括

1  流复用

SPDY最牛逼的地方,是允许在一个TCP连接里面,允许无限并发流(在双方资源可承受的情况下)。因为请求是在一个单一的通道交错传输,TCP的可以达到很高的效率,从而更少的网络连接需要,可以以很高的 数据密度做传输。
2  具备优先级的请求
虽然无限的并行数据流的解决了序列化的问题,但是它们引入了另一个问题:如果由于信道带宽的限制,客户端可能会阻止怕堵塞通道的要求。为了克服这个问题,SPDY实现请求的优先次序:客户端可以请求尽可能多的项目,每个请求分配一个优先级。这样即使高优先级的请求仍处在pending状态,通道也不会传输非关键的,低优先级的请求,这样就有效地阻止了传输拥塞。
3  HTTP Header 压缩
对于HTTP 请求,响应头,SPDY都做了压缩,这样包更小,对于RESTFUL类型的WEB2.0 ,or OpenAPI 业务,将会有可观的效率提升。
高级特性

1  服务器端推送
SPDY通过X-Associated-Content 协议头来向客户端推送数据,头通知客户端,我要向你推送资源,准备接收好了。最近火爆的Google+ ,如果你用chrome浏览器,默认就采用SPDY技术,并且开启了服务器推送技术。服务器的推技术,全面提升了用户体验,是G+ 产品很快占据了足够多的优势,最近Facebook 开发自己的浏览器,也有摆脱现在技术限制的考虑
2  服务器暗示
不像上面提到的PUSH 技术,服务器会先告诉浏览器,你可以下载ABC资源了,这个ABC资源,可能就是下一个页面的JS ,CSS ,或者内容。服务器不会主动推送的,仍旧等待客户端请求,这对于低速网络,是个很大的优化,有点类似于我们的预加载技术
效果测试
TOP25 网站的平均页面加载时间

DSL 2 Mbps downlink, 375 kbps uplink Cable 4 Mbps downlink, 1 Mbps uplink

Average ms Speedup Average ms Speedup
HTTP 3111.916
2348.188
SPDY basic multi-domain* connection / TCP 2242.756 27.93% 1325.46 43.55%
SPDY basic single-domain* connection / TCP 1695.72 45.51% 933.836 60.23%
SPDY single-domain + server push / TCP 1671.28 46.29% 950.764 59.51%
SPDY single-domain + server hint / TCP 1608.928 48.30% 856.356 63.53%
SPDY basic single-domain / SSL 1899.744 38.95% 1099.444 53.18
SPDY single-domain + client prefetch / SSL 1781.864 42.74% 1047.308 55.40%

转:JVM伪共享

   伪共享False sharing说明JVM底层技术也不让人那么放心。

内存缓存系统中基本单元是高速缓存行(Cache lines). cpu会把数据从内存加载到高速缓存中 ,这样可以获得更好的性能,高速缓存默认大小是64 Byte为一个区域,一个区域在一个时间点只允许一个核心操作,也就是说不能有多个核心同时操作一个缓存区域。

因为高速缓存是64字节,而Hotspot JVM的对象头是两个部分组成,第一部分是由24字节的hash code和8字节的锁等状态标识组成,第二部分是指向该对象类的引用。基本类型字节如下:
doubles (8) and longs (8)
ints (4) and floats (4)
shorts (2) and chars (2)
booleans (1) and bytes (1)
references (4/8)

因此,一个高速缓存64字节可以放下多个字段,如果这多个字段位于同一个高速缓存区,虽然它们是类的不同字段,如下代码:
Class A{
   int x;
   int y;
}
x和y被放在同一个高速缓存区,如果一个线程修改x;那么另外一个线程修改y,必须等待x修改完成后才能实施。
虽然两个线程修改各种独立变量,但是因为这些独立变量被放在同一个高速缓存区,性能就影响了。测试结果如后面。
当多核CPU线程同时修改在同一个高速缓存行各自独立的变量时,会不自不觉地影响性能,这就发生了伪共享False sharing,伪共享是性能的无声杀手。

解决方便是将高速缓存剩余的字节填充填满(pad),确保不发生多个字段被挤入一个高速缓存区,下面测试结果图就是和填充后性能比较。

实现字节填充的框架有 Disruptor,在RingBuffer中实现填充。关于Disruptor可见infoQ这个视频,用1毫秒的延时得到100K+ TPS吞吐量,JDK的ArrayQueue并行环境不见得是最快的,该视频后面讨论很多,让人大跌眼镜啊,开放源码多有好处啊,别人能发现你不能发现的漏洞。另外一篇解剖Disruptor

C#也有类似伪共享发生,见这里
jvm_False_sharing.png
参考:http://www.jdon.com/jivejdon/thread/42451
LMAX架构
disruptor - 并发编程框架
http://www.infoq.com/presentations/LMAX
    Page :
  1. 1
  2. 2
  3. 3
  4. 4
  5. 5
  6. 6
  7. ...
  8. 40