1.记一次源码追踪分析,俩瓜从Java到JNI,源码再到JVM的俩瓜C++:fileChannel.map()为什么快;源码分析map方法,put方法
2.如何创建网站后台
记一次源码追踪分析,源码从Java到JNI,俩瓜再到JVM的源码胸衣源码C++:fileChannel.map()为什么快;源码分析map方法,put方法
前言
在系统IO相关的俩瓜系统调用有read/write,mmap,源码sendfile等这些。俩瓜
其中read/write是源码普通的读写,每次都需要将buffer从用户空间拷贝到内核空间;
而mmap使用的俩瓜是内存映射,会将磁盘文件对应的源码页映射(拷贝)到内核空间的page cache,并记录到用户进程的俩瓜页表中,使得用户空间也可以像操作用户空间一样操作该文件的源码映射,最后再由操作系统来讲该映射(脏页)回写到磁盘;
sendfile则使用的俩瓜是零拷贝技术,在mmap的基础上,当发送数据的时候只拷贝fd和offset等元数据信息,而将数据主体直接拷贝至protocol buffer,实现了内核数据零冗余的零拷贝技术
本文地址:/post//
问题/目的问题1Java中哪些API使用到了mmap问题2怎么知道该API使用到了mmap,如何追踪程序的系统调用目的1源码中分析验证,从Java到JNI,再到C++:fileChannel.map()使用的是系统调用mmap目的2源码验证分析:调用mmapedByteBuffer.put(Byte[])时JVM在搞些什么?mmap比普通的read/write快在哪?揭晓答案1mmap在Java NIO中的体现/使用看一个例子
// 1GBpublic static final int _GB = 1**;File file = new File("filename");FileChannel fileChannel = new RandomAccessFile(file, "rw").getChannel();MappedByteBuffer mmapedByteBuffer = fileChannel.map(FileChannel.MapMode.READ_WRITE, 0, _GB);for (int i = 0; i < _GB; i++) { count++;mmapedByteBuffer.put((byte)0);}其中fileChannel.map()底层使用的就是系统调用mmap,函数签名为: public abstract MappedByteBuffer map(MapMode mode,long position, long size)throws IOException
答案2程序执行的系统调用追踪/** * @author Tptogiar * @description * @date /5/ - : */public class TestMappedByteBuffer{ public static final int _4kb = 4*;public static final int _GB= 1**;public static void main(String[] args) throws IOException, InterruptedException { // 为了方便在日志中找到本段代码的开始位置和结束位置,这里利用文件io来打开始标记FileInputStream startInput = null;try { startInput = new FileInputStream("start1.txt");startInput.read();} catch (IOException e) { e.printStackTrace();}File file = new File("filename");FileChannel fileChannel = new RandomAccessFile(file, "rw").getChannel();MappedByteBuffer map = fileChannel.map(FileChannel.MapMode.READ_WRITE, 0, _GB); //我们想分析的语句问题2for (int i = 0; i < _GB; i++) { map.put((byte)0); // 下文中需要分析的语句目的2}// 打结束标记FileInputStream endInput = null;try { endInput = new FileInputStream("end.txt");endInput.read();} catch (IOException e) { e.printStackTrace();}}}把上面这段代码编译后把“.class”文件拉到linux执行,并用linux上的strace工具记录其系统调用日志,拿到日志文件我们可以在日志中看到以下信息(关于怎么拿到日志可以参照我的博文:无(代写)):
注:日志有多行,这里只选取我们关注的
// ...// 看到了我们打的开始标志openat(AT_FDCWD, "start1.txt", O_RDONLY) = -1 ENOENT (No such file or directory)// ... // 打开文件,文件描述符fd为6openat(AT_FDCWD, "filename", O_RDWR|O_CREAT, ) = 6// 判断文件状态fstat(6, { st_mode=S_IFREG|, st_size=, ...}) = 0// ... // 判断文件状态fstat(6, { st_mode=S_IFREG|, st_size=, ...}) = 0// 进行内存映射mmap(NULL, , PROT_READ|PROT_WRITE, MAP_SHARED, 6, 0) = 0x7f2fd6cd// ...// 程序退出exit(0)// 看到了我们打的结束标志openat(AT_FDCWD, "end.txt", O_RDONLY) = -1 ENOENT (No such file or directory)在上面程序的系统调用日志中我们确实看到了我们打的开始标志,结束标志。在开始标志和结束标志之间我们看到了我们的文件"filename"确实被打开了,文件描述符fd = 6;在打开文件后紧接着又执行了系统调用mmap,这一点我们Java代码一致,这样,我们就验证了我们答案1中的结论,可以开始我们的下文了
源码追踪分析,从Java到JNI,再到JVM的swap源码C++目的1寻源之旅:fileChannel.map()我们知道我们执行Java代码fileChannel.map()确实会在底层调用系统调用,那怎么在源码中得到验证呢?怎么落脚于源码进行分析呢?下面开始我们的寻源之旅
FileChannelImpl.map() 注:由于代码较长,这里代码中略去了一些我们不关注的,比如异常捕获等
public MappedByteBuffer map(MapMode mode, long position, long size)throws IOException{ // ...try { // ...synchronized (positionLock) { // ...long mapPosition = position - pagePosition;mapSize = size + pagePosition;try { // !我们要找的语句就在这!addr = map0(imode, mapPosition, mapSize);} catch (OutOfMemoryError x) { // 如果内存不足,先尝试进行GCSystem.gc();try { Thread.sleep();} catch (InterruptedException y) { Thread.currentThread().interrupt();}try { // 再次试着mmapaddr = map0(imode, mapPosition, mapSize);} catch (OutOfMemoryError y) { // After a second OOME, failthrow new IOException("Map failed", y);}}} // ...} finally { // ...}}上面函数源码中真正执行mmap的语句是在addr = map0(imode, mapPosition, mapSize),于是我们寻着这里继续追踪
FileChannelImpl.map0()
// Creates a new mappingprivate native long map0(int prot, long position, long length)throws IOException;可以看到,该方法是一个native方法,所以后面的源码我们需要到这个FileChannelImpl.class对应的fileChannelImpl.c中去看,所以我们需要去找到JDK的源码
在JDK源码中我们找到fileChannelImpl.c文件
fileChannelImpl.c 根据JNI的对应规则,我们找到该文件内对应的Java_sun_nio_ch_FileChannelImpl_map0方法,其源码如下:
JNIEXPORT jlong JNICALLJava_sun_nio_ch_FileChannelImpl_map0(JNIEnv *env, jobject this, jint prot, jlong off, jlong len){ void *mapAddress = 0;jobject fdo = (*env)->GetObjectField(env, this, chan_fd);jint fd = fdval(env, fdo);int protections = 0;int flags = 0;if (prot == sun_nio_ch_FileChannelImpl_MAP_RO) { protections = PROT_READ;flags = MAP_SHARED;} else if (prot == sun_nio_ch_FileChannelImpl_MAP_RW) { protections = PROT_WRITE | PROT_READ;flags = MAP_SHARED;} else if (prot == sun_nio_ch_FileChannelImpl_MAP_PV) { protections =PROT_WRITE | PROT_READ;flags = MAP_PRIVATE;}// !我们要找的语句就在这里!mapAddress = mmap(0,/* Let OS decide location */len,/* Number of bytes to map */protections,/* File permissions */flags,/* Changes are shared */fd, /* File descriptor of mapped file */off); /* Offset into file */if (mapAddress == MAP_FAILED) { if (errno == ENOMEM) { JNU_ThrowOutOfMemoryError(env, "Map failed");return IOS_THROWN;}return handle(env, -1, "Map failed");}return ((jlong) (unsigned long) mapAddress);}我们要找的语句就上面代码中的mapAddress = mmap(0,len,protections,flags,fd,off),至于为什么不是直接的mmap,而是mmap,是因为这里的mmap是一个宏,在文件上方有其定义,如下:
#define mmap mmap至此,我们就在源码中得到验证了我们问题2中的结论:fileChannelImpl.map()底层使用的是mmap系统调用
目的2寻源之旅:mmapedByteBuffer.put(Byte[ ])接着我们来看看当我们调用mmapedByteBuffer.put(Byte[])JVM底层在搞些什么动作
MappedByteBuffer ?首先我们得知道,当我们执行MappedByteBuffer map = fileChannel.map(FileChannel.MapMode.READ_WRITE, 0, _GB)时,实际返回的对象是DirectByteBuffer类的实例,因为MappedByteBuffer为抽象类,且只有DirectByteBuffer继承了它,看下面两图就明白了
DirectByteBuffer 于是我们找到DirectByteBuffer内的put(Byte[ ])方法
public ByteBuffer put(byte x) { unsafe.putByte(ix(nextPutIndex()), ((x)));return this;}可以看到该方法内实际是调用Unsafe类内的putByte方法来实现功能的,所以我们还得去看Unsafe类
Unsafe.class
public native voidputByte(long address, byte x);该方法在Unsafe内是一个native方法,所以所以我们还得去看unsafe.cpp文件内对应的实现
unsafe.cpp
在JDK源码中,我们找到unsafe.cpp
在这份源码内,没有使用JNI内普通加前缀的方法来形成对应关系
不过我们还是能顺着源码的蛛丝轨迹找到我们要找的方法
注意到源码中有这样的注册机制,所以我们可以知道我们要找的代码就是上图中标注的代码
顺藤摸瓜,我们就找到了该方法的定义
UNSAFE_ENTRY(void, Unsafe_SetNative##Type(JNIEnv *env, jobject unsafe, jlong addr, java_type x)) \UnsafeWrapper("Unsafe_SetNative"#Type); \JavaThread* t = JavaThread::current(); \t->set_doing_unsafe_access(true); \void* p = addr_from_java(addr); \*(volatile native_type*)p = x; \t->set_doing_unsafe_access(false); \UNSAFE_END \该方法内主要的逻辑语句就是以下两句:
/** * @author Tptogiar * @description * @date /5/ - : */public class TestMappedByteBuffer{ public static final int _4kb = 4*;public static final int _GB= 1**;public static void main(String[] args) throws IOException, InterruptedException { // 为了方便在日志中找到本段代码的开始位置和结束位置,这里利用文件io来打开始标记FileInputStream startInput = null;try { startInput = new FileInputStream("start1.txt");startInput.read();} catch (IOException e) { e.printStackTrace();}File file = new File("filename");FileChannel fileChannel = new RandomAccessFile(file, "rw").getChannel();MappedByteBuffer map = fileChannel.map(FileChannel.MapMode.READ_WRITE, 0, _GB); //我们想分析的语句问题2for (int i = 0; i < _GB; i++) { map.put((byte)0); // 下文中需要分析的语句目的2}// 打结束标记FileInputStream endInput = null;try { endInput = new FileInputStream("end.txt");endInput.read();} catch (IOException e) { e.printStackTrace();}}}0至此,我们就知道:其实我们调用mmapedByteBuffer.put(Byte[ ])时,JVM底层并不需要涉及到系统调用(这里也可以用strace工具追踪从而得到验证)。也就是说通过mmap映射的空间在内核空间和用户空间是共享的,我们在用户空间只需要像平时使用用户空间那样就行了————获取地址,设置值,而不涉及用户态,内核态的smartconfig源码切换
总结fileChannelImpl.map()底层用调用系统函数mmap
fileChannelImpl.map()返回的其实不是MappedByteBuffer类对象,而是DirectByteBuffer类对象
在linux上可以通过strace来追踪系统调用
JNI中“.class”文件内方法与“.cpp”文件内函数的对应关系不止是前缀对应的方法,还可以是注册的方式,这一点的追寻代码的时候有很大帮助
directByteBuffer.put()方法底层并没有涉及系统调用,也就不需要涉及切态的性能开销(其底层知识执行获取地址,设置值的操作),所以mmap的性能就比普通读写read/write好
...
原文:/post/如何创建网站后台
网站后台制作流程网上有很多网站的后台制作流程,但我比较喜欢的一个是:一、网站规划阶段
这个阶段主要是对网站的功能、目标受众、内容、栏目进行规划。在此期间,我们会定期与相关领导沟通。首先你要明确网站的整体规划,然后你要吸收别人的建议。吸收别人建议的过程可以认真做,也可以走过场,但经过这个过程,别人就不会对你的方案说三道四了。
至于领导的意愿,与你的计划密切相关的是什么,你必须让领导知道,他们的想法在你的计划中已经考虑进去了。
项目的大致进度应在此阶段结束时确定。
二、后台模块划分、网站模板、网站设计和版面设计
在这个阶段,程序员和美国工程师将以两种方式分开。
后台模块划分做得好,后期效率会更高。无法保存此流程。
版面设计和美工设计既要考虑网站的整体规划,也要考虑大家的建议,尤其是领导的看法(虽然大多数情况下,领导的卖出 源码美工细胞少得可怜)。在这个大前提下,审美和理性都要兼顾。一个好的美工不仅能做出漂亮的页面,还能迎合客户或公司领导的意愿,与程序员沟通。
在这个阶段,程序员和项目经理(项目负责人)要拿出一个可操作的模块划分方案,美工要确定网站的布局框架和美术风格,做好网站的首页和二级页面。
其实在第一阶段(网站策划阶段),美工就要开始思考网站的风格了。第二阶段,要把抽象的初级思想变成具体的页面。基本上设置了首页,整个网站一半以上的页面都设置好了。
在这一阶段结束时,应进一步规定项目的时间表。
第三,数据库设计
这项工作非常重要。但是程序员应该知道怎么做。而且数据库设计与一个人的理论水平和实践经验息息相关,不是三言两语能说清楚的。对于大型复杂的网站,数据库规划可能需要一周左右,对于小型简单的网站,数据库设计也需要2到3天。
在这个阶段,美工最好不要闲着,继续完成页面设计。为了知道下一个阶段,程序员将不得不使用艺术家的页面。最好不要出现这样的情况:程序员想用某个页面,美工还没决定那个页面。
第四,后台程序编码
到了这个阶段,程序员就很难再努力了。tkinter源码
程序员需要遵循的三个原则:
1.团队合作;
2.确保进度;
3.保证质量。
这时候美工要辅助程序员做页面。在这个阶段,艺术家可能很闲,但一定要胜任。
当项目经理应该与客户或领导沟通时,他必须这样做。
5.调试、改进和页面美化
虽然以上是很多人开发网站的过程,但是我觉得这个想法很好。一个人做到了,各种事情就凑在一起了。首先,不要着急,你要把所有的线索都梳理好。其实我觉得你先做前台还是先做后台都无所谓。最重要的是,你必须协调处理好各方面的问题。一个网站只能事半功倍,不同的问题可以用不同的方法解决。可能有的网站需要先做前台,有的网站需要先做后台,等等。以上是我对做网站的一点拙见。
怎么如何自己建立创建网站论坛?
1
首先,买服务器并且注册好域名,百度一下就有,比如腾讯云,阿里云。百度云,都有云服务器和域名可以注册购买。
对于新手,我推荐选择WindowsServerr2的服务器系统,因为好操作,入手也快,比如我现在就买了一台,而且还要注册一个域名,域名备案的话我就不多说了,每一个注册域名的网站,都会有傻瓜式域名备案指引,或者买香港服务器,就可以不需要备案。
2
服务器,域名准备好了,就该在服务器搭建网站环境,这里选择最快捷的,直接下载phpstudy安装,然后打开,那么你的服务器就瞬间拥有php整合环境,根本就没有什么复杂的操作,其实把你的电脑作为本地环境也可以下载这个软件,总之功能强大,使用难度很低。
3
phpstudy安装好了,就打开面板,找到-其他选项菜单-站点域名管理,在里面设置网站域名和网站目录,域名就是你之前自己注册的,目录就是源代码该放进去的地方,同时确保端口为,比如我设置的目录就是D:phpStudyWWW
4
现在就该准备discuz源代码了,直接百度discuz就可以从官网下载到最新版,建议选择utf,因为这样在香港或者国外访问你的网站才不会乱码,而且个人感觉比gbk的漏洞少一些,把解压出来的源码放进你之前设置的网站目录。然后解析你的域名,A解析到你的服务器ip,这个域名管理面板也是傻瓜式操作,百度一下有很多教程,就不详细说明。
5
这些代码放到之前的www目录,确保你的域名解析好了,就在地址栏访问试试,然后就会出现安装界面了,不过在这之前,需要在添加一个数据库。phpstudy面板找到MySQL管理器,选择PHPmyadmin,然后点进去,用户名密码都填root。为了安全和复杂性,我们还是新增一个用户,设置得复杂一些,在面板中找到“用户”。
6
很明显的“增加用户”就在这里,然后就点进去吧
7
这里填写完毕,主机那里填写localhost,底下那里选择“创建与用户同名的数据库并授予所有权限”就好,然后最下面那些别管,就把上面的填好,就行了。
END
网站安装开始
现在可以访问域名,看到如下界面。然后一直确定和下一步,到达数据库信息填写。
除了数据库前缀,其它的都按自己之前的设置填写,因为之前设置了创建与用户同名的数据库并授予所有权限”那么数据库名和数据库用户名是一摸一样的,数据表前缀就别修改,然后填写好了,就下一步,随后一直等待,直到此页面出现,安装就完成了。
3
最底下有个您的论坛已完成安装,点此访问,然后点击,就可以进入论坛首页了,就此论坛安装完成,不过大家可以看到页面很丑,但是请别失望,因为discuz有许多的精美模板,登录后台找到应用,就可以进去寻找模板,下载安装,也可以百度去一些源码网站下载模板,手机电脑都有,同时也提供插件扩展。
后台地址:域名/admin.php开启云平台及QQ微信登录:域名/admin.php?action=cloudoperation=open后台功能很多,各位站长慢慢研究吧,也可以在自己电脑尝试一下,那么访问你的网站就用.0.0.1这个ip或者localhost
如何进入网站的后台?
一般情况下网站的后台都有默认的地址你建议你试一下以下后缀的地址
/admin/index.asp
/admin/login.asp
/admin/admin_login.asp
/manage/index.asp
/manage/login.asp
/manage/admin_login.asp
/admin/index.aspx
/admin/login.aspx
/admin/admin_login.aspx
/manage/index.aspx
/manage/login.aspx
/manage/admin_login.aspx
网站(英文:Website)是指在互联网上根据一定的规则,使用HTML等工具制作用于展示特定内容的相关网页的集合。世界上第一个网站由蒂姆·伯纳斯-李创建于年。网站是一种通信工具,人们可以通过网站来发布自己想要公开的信息,或者利用网站来提供相关的网络服务。人们可以通过网页浏览器来访问网站,获取自己需要的信息或者享受网络服务。现在许多公司都拥有自己的网站,他们利用网站来行宣传、发布产品信息、招聘等等。随着网页制作技术的流行,很多个人也开始制作个人网站,这些通常是制作者用来自我介绍、展现个性的地方。也有以提供网络信息为盈利手段的网络公司,通常这些公司的网站上提供人们生活各个方面的信息如时事新闻、旅游、娱乐、经济等。如何制作一个企业网站,建设网站的基本步骤有哪些?
1、首先要知道我们要干什么
在做网站之前我们先要知道我们为什么要做网站,要让网站起到什么作用,这个非常重要,网站建设一定要有目的性,想好需要做的是什么类型的网站,对网站的主要内容和主题有明显的确定。
2、整理网站所需资料
资料:网站的域名、网站的空间、网站所需要展示的内容(产品、案例、服务项目、公司介绍等)以及网站所需的一些推广等。资料的收集需要围绕着主题来看,想要让自己的网站内容更加的丰富,能够吸引用户,就需要尽量多的进行资料的收集和整理,只要资料更加丰富的话,在建站方面也就越容易。
3、设计网站页面
网站页面是非常重要的,用户通过网站页面来了解我们所要推广的信息,对于一个网站来说是不是成功的,在很大程度上的都是归功于设计者的规划水平,在进行规划的时候有很多方面的内容是需要我们考虑的,比如说是整体的结构、导航栏分类、主题色调、网站的风格、版面布局以及内部的文字等等,这样子最后做出来的网站才能够驾轻就熟,具有吸引力。
4、制作网站
网站页面设计出来之后,就需要前台开发人员将设计好的页面制作成网页,同时后台程序人员通过编程使网站的功能一一实现,这是一个比较复杂的过程,可以按照先从大的方面进行考虑、复杂的先来,然后才是细节部分和简单的部分。这样子在网站出现了一些问题的时候可以更好的进行修改。
5、内容完善
网站制作完成,我们通过测试无误之后,就需要把网站进行发布,通过域名绑定解析服务器,可以使我们通过互联网访问到网站,同时将我们所要在网站呈现内容都一一上传,如企业产品、案例展示等等。
网站前后台怎么连接?
前台与后台的连接,一般都有一些比较通用的设计,如JAVA的SSH三层架构。如根据学号查询成绩。1首先编写一个html的网页,里面要设计一个可以输入学号的文本框,用来接收用户填写的学号;并添加一个区域用来显示结果。2在后台编写可接收前台请求的程序,如action或servlet3在网页中设计好提交到后台的请求路径,及提交的参数(如上面的学号);4在后台编写业务逻辑服务代码,并调用数据库进行查询,并将结果返回给页面;5在页面预留位置,将结果展示出来。
怎样进入网站的后台?
知道网站的后台登陆用户名和密码!然后在后台登录窗口进入就可以了,如果你是高级会员可以随意玩,普通会员大多是只有局部的功能!这要看你的网站是什么类型的了!