2014年5月

Java String.intern() 方法

是什么? 为什么?

看到有个统计说, 在 JVM 的内存中, String 大概占到20% ~ 50% 的内存区, 那么这么多的 String 必定有很多重复的, 既然是重复的, 那就可以只在内存放一份, 所有使用这个 String 的 reference 都指向同一块内存. 那么 JVM 就在 permanet generation 放置了一个 StringSet(也有称 StringTable, StringCache), 当一个 String instance 调用 intern 方法的时候, 它先检查这个 String 在 StringSet 中是否存在, 如存在, 就返回这个存在的 String, 否则, 在 StringSet 中添加这个 String, 并且返回新加的这个 String.
这前提是基于: Java 的 String 是 immutable 的: 如果你改变了 String 的一部分, 原来的 reference 就指向了一个新的String. 如果都在原来的 String 的内存区修改, 那么就不能放到 StringSet 了.
另外, 编译器自动把你程序中的类名, 方法名, String 常量值, 字面值 等都事先放入了 StringSet. 这个 StringSet 是有 String 这个 class 所管理的.
类似的机制, 在整数类型 (Byte, Short, Integer, Long) 的 valueOf 方法中都有体现, 默认 -128 ~ 127 都放入了 cache.

优缺点?

如果你有大量的重复的 String 值要在程序中使用, 并且是运行时生成的 String, 通过 intern 方法, 会大大节省内存, 并且减少 GC 的量. 但是, 带来是效果是需要能多的时间. 时间 VS 内存. 关于时间和内存的比较, 详细可以看 refer 2.

如果是仅仅使用 intern 的值来用 == 对比, 完全没有必要, 时间上算起来, 差不多.


摘抄:
String interning takes a String instance (so it already exists in the Heap) and checks if an identical copy exists already in a StringTable.
That StringTable is basically a HashSet that stores the String in the Permanent Generation. The only purpose of that Table is to keep a single instance of the String alive. If it is in there, the instance is returned. If its not, its added to the String Table
Note that ALL Strings which are hardcoded (as constant or anywhere in code) are automatically interned by the compiler.

参考:

  1. Save Memory by Using String Intern in Java
  2. String spec

网站访问 -> 代理 ip 检测 -> 端口扫描 -> nmap

看网站的后台浏览记录, 最近发现经常有这么一个网址: mianfeidaili.ttju.cn, 入口是这个网址, 浏览页面竟然也是这个网址. 可以猜测这是一个网页代理, 因为是访问的这个页面, 所以入口和浏览页面的网址都是这个页面.

顺着这个网址找过去, 发现是个: "提供代理IP提取" 的网站. 百度了一下, 发现类似的网站都是提供代理 ip 地址的. 通过某些扫描软件, 发现某一网段, 或者某一运营商(电信,联通,移动)的 ip 段内的免费代理. 然后卖个用户, 用户可以用这些代理刷投票等.

ip 端检测方面比较出名的是 nmap, 它可以 1) 检测该 ip 是否有对应的主机, 该主机是否 up, 2) 那些端口是对外开放的, 是什么协议, 3) 对应的操作系统是什么.

路由器 repo 上竟然有 nmap 软件, 安装之后试了试, 基本的扫描主机还可以. 如果扫描端口什么的, CPU 就飙升了.

eric@home:/tmp/home/eric# nmap -PS21 223.166.19.225/29

Starting Nmap 5.35DC1 ( http://nmap.org ) at 2014-05-25 17:44 UTC
Nmap scan report for 223.166.19.225
Host is up (0.00070s latency).

Nmap scan report for 223.166.19.226
Host is up (0.0027s latency).
Not shown: 997 closed ports
PORT     STATE    SERVICE
23/tcp   filtered telnet
80/tcp   open     http
1900/tcp open     upnp

Nmap done: 8 IP addresses (2 hosts up) scanned in 2138.07 seconds

如上所示, 我扫描了一下我主机所在的 IP 段的一个非常小的部分. 共有8个 IP 地址, 有2个主机 up, 其中上面那个是我的路由器. 下面是另外一台在线的主机. 竟然开着80端口. 不过80端口返回403. 另外还开着1900, 是 upnp 协议.

单例模式 -> ThreadLocal -> new

Java 是多线程, 面向对象的编程语言. 多线程有时候也需要 share 一个实例对象. 一个 JVM 中的多线程可能会产生如下的 share 模式:

  1. 所有线程使用同一个实例对象: 单例模式;
  2. 每个线程使用一个实例对象: ThreadLocal;
  3. 最普遍的, 一个实例对象就是内存堆中的一个实例对象: new

如何做到一个 JVM 中的 单例模式:

  1. 构造函数全都是 private
  2. 因为构造函数是 private, 所以只能该 class 提供一个唯一内部的 static instance. 该 static instance 可以通过 public 暴露, 或者通过一个 public static 方法暴露. 通过方法暴露, 可以 lazy init;

其实, 如上并不能保证一个 JVM 中只有一个 instance, 比如2个 ClassLoader 在同一级, 分别 load 该 class, 或者反序列化该类;

ThreadLocal

前面要加 static final 修饰符. 不加 static, 不能确保一个线程只有一个实例. 不加 final, 可能会被改变的

How to create a java object?

  1.    new Object();
    
  2.    Class.forName(“com.txhcqy.A”).newInstance();
    
  3.    反序列化
    
  4.    反射机制中的Constructor
    

git 学习笔记 之 服务器上的 Git

原书中文版网址: here

为什么需要远程 git repo? 共享, 合作, 集成, 备份?
本地 repo <- pull, push -> 远程 repo
远程 repo 没有人在开发 -> no work directory -> so bare repository -> just need files in .git folder
git repo 所管理的所有东西, 都是 .git 目录下的文件 -> 它根据 git 自己定义的组织结构存在

架设 "git server" -> 通信 -> 选择协议 (file, ssh, http/https, git).

file 本地共享, 方便, 不安全, 灾难备份, 有时候许挂载;
ssh 同时支持 读, 写的网络协议, ssh 最常见, 安全, 基于用户名密码访问, 不利于共享, 和匿名访问;
git 自带的守护线程(9418), 需要 git-daemon-export-ok 文件, 没有加密&授权机制, 要么全部允许推送, 要么全部不允许;
http/https 简便, 便于分享, 需要 post-update hook, 如果需要推送 -> WebDAV, 端口常见, 效率低

"git server" 的关键点在于管理用户权限, ssh for each user? or shared account? or LDAP integratoin?

gitosis 可以帮我们管理 authorized_keys 中所有的 public key;
貌似Gitolite 更强大, 管理的细节竟然到了某 branch, refs 了.

服务器上的 git, 而不是 git server

上周看到 ddwrt 的 repo 中有 git, 就突发奇想, 是不是可以在路由器上搭一个 git server.
后来发现, 其实并没有 git server, 只有 server 上的 git.

首先, git 维护的是 .git 目录下面的所有文件和文件夹, repo 之间 push/pull 的效果是: .git 目录下面文件的相互 copy.
服务器上的 git 默认是没有监听线程的, 所以如果你 push, 其实是把文件 copy 到 server 上的某个 .git 文件夹下面. 一般我们用的还是 ssh 协议, 其实类是你 ssh 登录到 server, 然后用 vi 写 .git 文件夹下的文件.

所以最简单的 "git server" 是你在一个大家都可以访问的 server 初始化一个存放 .git 文件夹下所有文件的目录. 然后开放 ssh 协议, 凡是能够 ssh 登上这台 server 的人, 可以可以 push. pull 就是完全 copy 下来.

之所以有 git server 的惯性思维, 是因为我们经常用 github, gitlab 这样的 git web 管理 server, 是这些 web server 给了我们一个浏览我们 git 保存的历史版本的工具.

除了 github, gitlab (免费)之外, 还有一些比较方便的共享 repo 的方法 8 ways to share your git repository

另外: 服务器上的 Git - 协议