Compile-kernel-module

1. 内核模块编程
1.1 简介
1.2 加载内核模块
1.3 最简单的模块
1.4 模块必要信息
1.4.1 内核模块必须至少包含的头文件:
1.4.2 内核模块必须至少有两个功能:
1.4.3 printk()日志记录
1.4.4 优先级
1.4.5 许可和模块文档
1.5 编译内核模块
1.6 实战
1.6.1 源代码文件: hello.c
1.6.2 Makefile文件: Makefile
1.6.3 使用make编译
1.6.4 使用modinfo查看新的模块文件
1,6.5 使用insmod加载内核模块
1.6.6 使用lsmod查看已加载的模块
1.6.7 使用rmmod卸载模块
1.6.8 使用dmesg查看日志
1.6.9 练习
1.6.10 其他信息
1.7 更多基础示例链接
1.7.1 将命令行参数传递给模块
1.7.2 跨越多个文件的模块
1.7.3 构建预编译内核的模块
1.7.4 与应用程序交互
2 make工具
2.1 DESCRIPTION
2.2 退出状态
2.3 选项
3. 其他内核编译方法及相关连接
3.1 编译Arch的内核模块
3.2 Arch构建系统
3.3 内核/传统编译
3.4 修补包
3.5 模块与程序

1. 内核模块编程

http://www.tldp.org/LDP/lkmpg/2.6/html/
Linux内核模块编程指南 2007-05-18见2.6.4

1.1 简介

什么是内核模块?模块是可以根据需要加载和卸载到内核中的代码片段。它们扩展了内核的功能,而无需重启系统。
例如,一种类型的模块是设备驱动程序,它允许内核访问连接到系统的硬件。还有很多的文件系统等。

1.2 加载内核模块

您可以通过运行lsmod来查看已经加载到内核中的模块,lsmod通过读取文件/proc/modules来获取其信息。
执行modprobe来加载模块.modprobe以两种形式之一传递一个字符串:
  > 模块名称,如softdog或ppp。
  > 一个更通用的标识符,如char-major-10-30。
如果modprobe被赋予通用标识符,它首先在文件/etc/modprobe.conf中查找该字符串。如果找到如下的别名行:alias char-major-10-30 softdog
它知道通用标识符引用模块softdog.ko。
然后,modprobe查看文件/lib/modules/version/modules.dep,查看是否必须加载其他模块才能加载所请求的模块。该文件由depmod -a创建,包含模块依赖项。
      例如,msdos.ko要求fat.ko模块已经加载到内核中。
最后,modprobe使用insmod首先将任何必备模块加载到内核中,然后加载所请求的模块。
modprobe将insmod指向/lib/modules/'uname -r'/, 模块的标准目录。

insmod对于模块的位置是相当愚蠢的,而modprobe知道模块的默认位置,知道如何找出依赖关系并以正确的顺序加载模块。
因此,例如,如果要加载msdos模块,则必须运行:
$ insmod /lib/modules/2.6.11/kernel/fs/fat/fat.ko
$ insmod /lib/modules/2.6.11/kernel/fs/msdos/msdos.ko

要么:
$ modprobe msdos
所以,insmod要求你传递完整的路径名并以正确的顺序插入模块,而modprobe只取名字,没有任何扩展名,并通过解析/lib找出它需要知道的所有内容/modules/version/modules.dep。

1.3 最简单的模块

http://www.tldp.org/LDP/lkmpg/2.6/html/x121.html
Example 2-1. hello-1.c
#include <linux/module.h> /* Needed by all modules */
#include <linux/kernel.h> /* Needed for KERN_INFO */
int init_module(void)
{
printk(KERN_INFO "Hello world 1.\n");
return 0;
}
void cleanup_module(void)
{
printk(KERN_INFO "Goodbye world 1.\n");
}

1.4 模块必要信息

1.4.1 内核模块必须至少包含的头文件:

#include <linux/module.h> /* module_init() module_exit() 函数来注册模块入口和退出处理。
#include <linux/kernel.h> /* Needed for KERN_INFO ,仅用于printk()日志级别的KERN_ALERT的宏扩展 */
#include <linux/init.h> /* Needed for the macros */

1.4.2 内核模块必须至少有两个功能:

  • 一个“开始”(初始化)功能调用 的init_module()当模块insmoded到内核被称为,
  • 以及“结束”(清理)函数调用在cleanup_module()这是刚刚称为在它被破坏之前。

从Linux 2.4开始,您可以重命名模块的init和cleanup功能; 它们不再需要分别被称为 init_module()和cleanup_module()。
这是通过 module_init()和module_exit()宏完成的。这些宏在linux / init.h中定义。
唯一需要注意的是,必须在调用宏之前定义init和cleanup函数,否则会出现编译错误。

1.4.3 printk()日志记录

由于代码运行在内核空间里面,不能直接使用用户空间的 print 函数,而要使用内核中的 printk 函数.
作为日志记录机制,用于记录信息或发出警告。
每个printk() 语句都带有一个优先级,即您看到的<1>和KERN_ALERT。
有8个优先级,内核有宏,所以你不必使用神秘的数字,你可以在linux/kernel.h中查看它们(及其含义)。
如果未指定优先级,则将使用默认优先级DEFAULT_MESSAGE_LOGLEVEL。

花点时间阅读优先级宏。头文件还描述了每个优先级的含义。
在实践中,不要使用数字,如<4>。始终使用宏,如 KERN_WARNING。

如果优先级低于int console_loglevel,则会在当前终端上打印消息。
如果syslogd和klogd都在运行,那么该消息也将附加到/var/log/messages,无论它是否打印到控制台。
我们使用高优先级(如KERN_ALERT)来确保将printk()消息打印到控制台而不是仅记录到日志文件中。
编写实际模块时,您需要使用对当前情况有意义的优先级。

1.4.4 优先级

https://szosoft.blogspot.com/2019/06/linux-journal.html#1021
cat  /usr/lib/modules/5.1.15-arch1-1-ARCH/build/include/linux/kernel.h
cat  /usr/lib/modules/5.1.15-arch1-1-ARCH/build/include/linux/printk.h

内核模块printk no (Key)journal
KERN_EMERG 0 Emergency 紧急
KERN_ALERT 1 Alert 警报
KERN_CRIT 2 Critical 危急
KERN_ERR 3 Error 错误
KERN_WARNING 4 Warning 警告
KERN_NOTICE 5 Notice 注意
KERN_INFO 6 Informational 信息
KERN_DEBUG 7 Debug 调试

1.4.5 许可和模块文档

MODULE_LICENSE("GPL");  /* Get rid of taint message by declaring code as GPL.  */
MODULE_AUTHOR("Tom"); /* Who wrote this module? */
MODULE_DESCRIPTION("Test"); /* What does this module do */
MODULE_VERSION("0.0.1");
MODULE_SUPPORTED_DEVICE("testdevice");   /* 声明模块支持哪些类型的设备。 */
在内核2.4及更高版本中,设计了一种机制来识别在GPL(和朋友)下许可的代码,以便可以警告人们代码是非开源的。
这是通过MODULE_LICENSE()宏实现的。通过将许可证设置为GPL,可以防止打印警告。
此许可证机制在linux/module.h中定义并记录:
$ cat  /usr/lib/modules/5.1.15-arch1-1-ARCH/build/include/linux/module.h |grep MODULE_

/*
 * 目前接受以下许可证标识为免费软件模块
 * "GPL" [GNU Public License v2 or later]
 * "GPL v2" [GNU Public License v2]
 * "GPL and additional rights" [GNU Public License v2 rights and more]
 * "Dual BSD/GPL" [GNU Public License v2 or BSD license choice]
 * "Dual MIT/GPL" [GNU Public License v2 or MIT license choice]
 * "Dual MPL/GPL" [GNU Public License v2 or Mozilla license choice]
 *
 * 以下其他标识可供选择
 * "Proprietary" [Non free products]
 */

1.5 编译内核模块

http://www.tldp.org/LDP/lkmpg/2.6/html/x181.html
内核模块的编译需要与常规用户空间应用程序略有不同。
以前的内核版本要求我们关注这些设置,这些设置通常存储在Makefile中。虽然按层次结构组织,但许多冗余设置在次级Makefile中累积并使它们变大并且难以维护。
幸运的是,有一种新方法可以做这些事情,称为kbuild,外部可加载模块的构建过程现在完全集成到标准内核构建机制中。
要了解有关如何编译不属于官方内核的模块的更多信息(例如本指南中的所有示例),请参阅文件 linux/Documentation/kbuild/modules.txt.

编译时通过一个 Makefile 文件进行,把这个 Makefile 文件置于 hello.c 同一目录下.
Makefile对格式有要求。每一行文本除非顶头开始,如果需要格式编排,不能使用空格键来控制文本行缩进,必须使用Tab键

1.6 实战

1.6.1 源代码文件: hello.c

/*  hello.c - Demonstrates module documentation. */
#include <linux/module.h> /* Needed by all modules */
#include <linux/kernel.h> /* Needed for KERN_INFO */
#include <linux/init.h> /* Needed for the macros */
#define DRIVER_AUTHOR "Peter Jay Salzman <p@dirac.org>"
#define DRIVER_DESC   "A sample driver"

static int __init init_hello(void)
{
printk(KERN_INFO "HelloWorld\n");
return 0;
}

static void __exit cleanup_hello(void)
{
printk(KERN_INFO "GoodbyeWorld\n");
}

module_init(init_hello);
module_exit(cleanup_hello);

MODULE_LICENSE("GPL");
MODULE_AUTHOR(DRIVER_AUTHOR); /* Who wrote this module? */
MODULE_DESCRIPTION(DRIVER_DESC); /* What does this module do */
MODULE_SUPPORTED_DEVICE("testdevice");

1.6.2 Makefile文件: Makefile

obj-m += hello.o

all:
make -C /lib/modules/$(shell uname -r)/build M=$(PWD) modules

clean:
make -C /lib/modules/$(shell uname -r)/build M=$(PWD) clean

从技术角度来看,第一行确实是必要的,为了方便起见,添加了“全部”和“清洁”目标。
现在您可以通过发出命令make来编译模块。您应该获得类似于以下内容的输出:

1.6.3 使用make编译

$ make
make -C /lib/modules/5.1.15-arch1-1-ARCH/build M=/home/toma/ko modules
make[1]: Entering directory '/usr/lib/modules/5.1.15-arch1-1-ARCH/build'
  CC [M]  /home/toma/ko/hello.o
  Building modules, stage 2.
  MODPOST 1 modules
  CC      /home/toma/ko/hello.mod.o
  LD [M]  /home/toma/ko/hello.ko
make[1]: Leaving directory '/usr/lib/modules/5.1.15-arch1-1-ARCH/build'

请注意,内核2.6引入了一种新的文件命名约定:内核模块现在具有.ko 扩展名(代替旧的.o扩展名),可以轻松地将它们与传统的目标文件区分开来。
原因是它们包含一个额外的.modinfo部分,其中保留了有关该模块的其他信息。我们很快就会看到这些信息有什么用处。
有关内核模块的Makefile的更多详细信息,请参见 linux/Documentation/kbuild/makefiles.txt .

$ ls -l   //编译后查看文件列表
name size
Makefile 154   //make文件
hello.c 786      //源文件
hello.ko 4528   //内核文件
hello.mod.c 646
hello.mod.o 2712
hello.o 2664   //目标文件
modules.order 30
Module.symvers 0

1.6.4 使用modinfo查看新的模块文件

$ modinfo hello.ko
filename:       /home/toma/ko/hello.ko
version:        0.0.1
description:    Test
author:         Tom
license:        GPL
srcversion:     BC3C3A49026E0297D738AE7
depends:      
retpoline:      Y
name:           hello
vermagic:       5.1.15-arch1-1-ARCH SMP preempt mod_unload

1,6.5 使用insmod加载内核模块

$ sudo insmod ./hello.ko

1.6.6 使用lsmod查看已加载的模块

$ lsmod |grep hello
Module                  Size  Used by
hello                  16384  0

1.6.7 使用rmmod卸载模块

$ sudo rmmod hello
$ lsmod |grep hello

1.6.8 使用dmesg查看日志

$ dmesg |tail
...
[562050.818179] HelloWorld
[562458.113633] GoodbyeWorld

1.6.9 练习

练习1
请参阅init_module()中 return语句上方的注释 ?将返回值更改为负值,重新编译并再次加载模块。怎么了?
$ sudo insmod ./hello-2.ko
insmod: ERROR: could not insert module ./hello-2.ko: Operation not permitted
$ dmesg |tail
...
[546135.110381] HelloWorld2.

练习2
将代码中许可的部分删除,再编译看看。
$ make
make -C /lib/modules/5.1.15-arch1-1-ARCH/build M=/home/toma/ko modules
make[1]: Entering directory '/usr/lib/modules/5.1.15-arch1-1-ARCH/build'
  CC [M]  /home/toma/ko/hello-1.o
  Building modules, stage 2.
  MODPOST 1 modules
style="color: red; font-size: xx-small;">WARNING: modpost: missing MODULE_LICENSE() in /home/toma/ko/hello-1.o
see include/linux/module.h for more information
  CC      /home/toma/ko/hello-1.mod.o
  LD [M]  /home/toma/ko/hello-1.ko
make[1]: Leaving directory '/usr/lib/modules/5.1.15-arch1-1-ARCH/build'

1.6.10 其他信息

现在看一下linux/drivers/char/Makefile的真实示例。
正如你所看到的,有些东西被硬件连接到内核(obj-y)但是那些obj-m去了哪里?
那些熟悉shell脚本的人很容易发现它们。
对于那些没有的,你看到的obj - $(CONFIG_FOO)条目会扩展为obj-y或obj-m,具体取决于CONFIG_FOO变量是否已设置为y或m。
虽然我们在这里,但那些正是你在linux/.config文件中设置的那种变量,最后一次你说make menuconfig 或类似的东西。

1.7 更多基础示例链接

1.7.1 将命令行参数传递给模块

http://www.tldp.org/LDP/lkmpg/2.6/html/x323.html

1.7.2 跨越多个文件的模块

http://www.tldp.org/LDP/lkmpg/2.6/html/x351.html

1.7.3 构建预编译内核的模块

http://www.tldp.org/LDP/lkmpg/2.6/html/x380.html

1.7.4 与应用程序交互

https://www.oschina.net/translate/writing-a-simple-linux-kernel-module

2 make工具

2.1 DESCRIPTION

make实用程序将自动确定需要重新编译大型程序的哪些部分,并发出命令以重新编译它们。
我们的示例显示了C程序,因为它们非常常见,但您可以使用make与任何编译语言,其编译器可以使用shell命令运行。
实际上,make并不仅限于程序。
您可以使用它来描述任何一些任务,其中某些文件必须在其他文件更改时自动从其他文件更新。

要准备使用make,您必须编写一个名为makefile的文件,该文件描述程序中文件之间的关系,以及用于更新每个文件的命令的状态。
在程序中,通常从目标文件更新可执行文件,而目标文件又通过编译源文件来完成。

一旦存在合适的makefile,每次更改一些源文件时,这个简单的shell命令:
make
足以执行所有必要的重新编译。
make程序使用makefile描述和文件的最后修改时间来决定需要更新哪些文件。
对于每个文件,它会发出makefile中记录的命令。

make执行makefile中的命令以更新一个或多个目标名称,其中name通常是程序。
如果不存在-f选项,make将按顺序查找 makefiles GNUmakefile, makefile, and Makefile, in that order.

(我们建议使用Makefile,因为它突出显示在目录列表的开头附近,紧邻其他重要文件,如README。)
检查的第一个名称,建议不要将GNUmakefile用于大多数makefile。
如果您具有特定于GNU make的makefile,则应使用此名称,并且其他版本的make不会理解该名称。
如果makefile为' - ',则读取标准输入。

2.2 退出状态

如果所有的makefile都被成功解析并且没有构建的目标失败,则GNU make退出状态为零。
如果使用-q标志并且make确定需要重建目标,则将返回状态1。
如果遇到任何错误,将返回状态2。

2.3 选项

-b, -m Ignored for compatibility. 忽略兼容性.
-B, --always-make Unconditionally make all targets. 无条件地制定所有目标.
-C DIRECTORY, --directory=DIRECTORY Change to DIRECTORY before doing anything. 在做任何事之前改为DIRECTORY.
-d Print lots of debugging information. 打印大量调试信息.
--debug[=FLAGS] Print various types of debugging information.  FLAGS可以用于所有调试输出(与使用-d相同),
b用于基本调试,v用于更详细的基本调试,i用于显示隐式规则,
j用于调用命令的详细信息,m用于在重新生成makefile时进行调试.
 使用n禁用所有先前的调试标志.
-e, --environment-overrides Environment variables override makefiles. 环境变量覆盖makefile.
--eval=STRING Evaluate STRING as a makefile statement. 将STRING评估为makefile语句.
-f FILE, --file=FILE, --makefile=FILE Read FILE as a makefile. 将FILE作为makefile读取.
-h, --help Print this message and exit. 打印此消息并退出.
-i, --ignore-errors Ignore errors from recipes.  忽略为重制文件而执行的命令中的所有错误.
-I DIRECTORY, --include-dir=DIRECTORY Search DIRECTORY for included makefiles. 搜索DIRECTORY以获取包含的makefile.
-j [N], --jobs[=N] Allow N jobs at once; infinite jobs with no arg. 一次允许N个工作;没有arg的无限工作.
-k, --keep-going Keep going when some targets can't be made. 当一些目标无法制作时继续前进.
-l [N], --load-average[=N],--max-load[=N] Don't start multiple jobs unless load is below N. 除非负载低于N,否则不要启动多个作业.
-L, --check-symlink-times Use the latest mtime between symlinks and target. 使用符号链接和目标之间的最新mtime.
-n, --just-print, --dry-run, --recon Don't actually run any recipe; just print them. 实际上不要运行任何配方;只需打印它们.
-o FILE, --old-file=FILE, --assume-old=FILE Consider FILE to be very old and don't remake it. 即使FILE很老,也不要重新生成它.
-O[TYPE], --output-sync[=TYPE] Synchronize output of parallel jobs by TYPE. 按TYPE同步并行作业的输出.
 当与-j并行运行多个作业时,请确保将每个作业的输出收集在一起,而不是穿插其他作业的输出.
 如果未指定type或是target,则将每个目标的整个配方的输出组合在一起.
 如果type为line,则配方中每个命令行的输出将组合在一起.
 如果type是recurse,则整个递归make的输出被组合在一起.
如果type为none,则禁用输出同步.
-p, --print-data-base Print make's internal database.  打印通过读取makefile产生的数据库(规则和变量值);
然后像往常一样或以其他方式指定执行.
要打印数据库而不尝试重新创建任何文件,请使用: make -p -f/dev/null.
-q, --question Run no recipe; exit status says if up to date. ``问题模式''.不要运行任何命令,也不要打印任何东西;如果指定的目标已经是最新的,则返回退出状态为零,否则返回非零值.
-r, --no-builtin-rules Disable the built-in implicit rules. 禁用内置隐式规则.
-R, --no-builtin-variables Disable the built-in variable settings. 禁用内置变量设置.
-s, --silent, --quiet Don't echo recipes.  无声操作;不要在执行时打印命令.
-S, --no-keep-going, --stop Turns off -k.  取消-k选项的效果.这是永远不必要的,
除了在递归make中,-k可能通过MAKEFLAGS从顶级make继承,
或者如果你在环境中的MAKEFLAGS中设置-k.
-t, --touch Touch targets instead of remaking them. 触摸目标而不是重新制作它们.
 这用于假装命令已完成,以欺骗未来的make调用.
--trace Print tracing information. 打印跟踪信息.
-v, --version Print the version number of make and exit. 打印make和exit的版本号.
-w, --print-directory Print the current directory. 打印当前目录.
--no-print-directory Turn off -w, even if it was turned on implicitly. 关闭-w,即使它是隐式打开的.
-W FILE, --what-if=FILE, --new-file=FILE, --assume-new=FILE Consider FILE to be infinitely new. 认为FILE是无限新的.
 没有-n,它几乎与在运行make之前在给定文件上运行touch命令相同,只是修改时间仅在make的想象中改变.
--warn-undefined-variables Warn when an undefined variable is referenced. 引用未定义的变量时发出警告.

3. 其他内核编译方法及相关连接

3.1 编译Arch的内核模块

https://wiki.archlinux.org/index.php/Compile_kernel_module
首先,您需要安装构建依赖项,例如compiler(base-devel)和linux-headers。

3.2 Arch构建系统

https://wiki.archlinux.org/index.php/Kernel/Arch_Build_System
https://www.kernel.org/doc/Documentation/kbuild/kconfig.txt
内核/Arch构建系统
该拱门构建系统可以用来构建基于官方的自定义内核的Linux软件包。
这种编译方法可以自动化整个过程,并且基于经过良好测试的软件包。
您可以编辑PKGBUILD以使用自定义内核配置或添加其他修补程序。
$ pacman -Ss asp
extra/asp 5-1    Arch Linux build source file management tool
安装的ASP封装和基devel的包组。
您需要一个干净的内核来开始自定义。通过运行以下命令从ABS获取最新的内核包文件到您的构建目录:
$ asp update linux
$ asp checkout linux
然后,从各自的源获取您需要的任何其他文件(例如,自定义配置文件,修补程序等)。

3.3 内核/传统编译

https://wiki.archlinux.org/index.php/Kernel/Traditional_compilation#Download_the_kernel_source
安装核心包
安装base-devel软件包组,其中包含必要的软件包,例如make和gcc。
还建议安装以下软件包,如默认的Arch内核PKGBUILD中所列:xmlto,kmod,inetutils,bc,libelf,git

3.4 修补包

https://wiki.archlinux.org/index.php/Patching_packages#Applying_patches
本文介绍如何创建以及如何在Arch Build System(ABS)中将补丁应用于包。
一个补丁描述了一组针对一个或多个文件线路的变化。补丁通常用于自动更改源代码。

3.5 模块与程序

http://www.tldp.org/LDP/lkmpg/2.6/html/x427.html
程序 模块
用户空间      内核空间
printf() printk()
main()开始 init_module或 通过module_init调用指定的函数 开始
  cleanup_module或 使用module_exit调用指定的函数 结束

Compile-kernel-module的更多相关文章

  1. OpenWrt Kernel Module Creation Howto

    OpenWrt Kernel Module Creation Howto About OpenWrt Kernel Module Compilation You are planning to com ...

  2. The vboxdrv kernel module is not loaded

    背景: 在没有关虚拟机的情况下, 直接关了电脑, 我的电脑系统是Centos 6 错误的提示: 在终端执行virtualbox -v 时提示 The vboxdrv kernel module is ...

  3. Xamarin.Android模拟器提示HAX kernel module is not Installed

    Xamarin.Android模拟器提示HAX kernel module is not Installed 错误信息:emulator : ERROR : x86 emulation current ...

  4. HAX kernel module is not installed

    dev.android.emulator.haxm 运行emulator -avd xxx来启动名为xxx的模拟器,但报如下错误: emulator: ERROR: x86 emulation cur ...

  5. emulator: ERROR: x86 emulation currently requires hardware acceleration!Please ensure Intel HAXM is properly installed and usable.CPU acceleration status: HAX kernel module is not installed!

    Android Studio 1.0 已经放出来了,以后的Android平台开发激昂逐步从Eclipse向Android Studio迁移,为了能不落伍我也特意从Google下载了Android St ...

  6. Compiling a kernel module for the raspberry pi 2 via Ubuntu host

    Compiling a kernel module for the raspberry pi 2 via Ubuntu host Normally compiling a kernel module ...

  7. Virtualbox报错------>make sure the kernel module has been loaded successfully

    错误描述 很久没有用virtualbox了,今天打算在virtualbox上安装一个Ubuntu系统的时候,新建好Ubuntu后启动的时候,直接报错: Cannot access the kernel ...

  8. qemu 出现Could not access KVM kernel module: No such file or directory failed to initialize KVM: No such file or directory

    使用qemu命令 qemu-system-x86_64 -hda image/ubuntu-test.img -cdrom ubuntu-16.04.2-server-amd64.iso -m 102 ...

  9. 如何处理VirtualBox启动错误消息:The vboxdrv kernel module is not loaded

    我在启动minikube时,遇到如下错误消息: Starting local Kubernetes v1.10.0 cluster... Starting VM... E1010 03:27:37.9 ...

  10. kernel/module.c

    #include <linux/errno.h>#include <linux/kernel.h>#include <asm/segment.h>#include ...

随机推荐

  1. S32K144之时钟配置

    一般来说,时钟精度.稳定性取决于所采用的时钟源,就MCU S32K来说如内部振荡器SIRC,FIRC,128KLPO,外部晶振等,跟所使用的外设(FTM, LPIT,LPT,RTC等)和哪一路输出时钟 ...

  2. HashMap 原理?jdk1.7 与 1.8区别

    HashMap 结构 以及 1.7 与 1.8 一.区别 01. jdk 1.7 用的是头插法,而jdk1.8以后使用的是尾插法?为什么这样做呢?因为 JDK 1.7 是用单链表进行纵向延伸,采用头插 ...

  3. python学习第一课

    第一课: 1.不要使用来路不明的软件 2.下载杀毒软件 3.不懂技术的人在技术人面前会显得愈发无知 4.python无所不能 需要掌握的知识: 1.python基本语法 2.文件处理 3.函数 4.模 ...

  4. Redis 事务在 SpringBoot 中的应用 (io.lettuce.core.RedisCommandExecutionException: ERR EXEC without MULTI)

    我们在 SpringBoot 中使用 Redis 时,会引入如下的 redis starter <dependency> <groupId>org.springframewor ...

  5. HashMap的应用

    HashMap <String,String> hsMap=new HashMap<String,String> hsMap.put("1","v ...

  6. C++中的四种类型转换运算符static_cast、dynamic_cast、const_cast和reinterpret_cast的使用

    1.上一遍讲述了C语言的隐式类型转换和显示类型转换,C语言之所以增加强制类型转换,就是为了强调转换的风险性,但这种强调风险的方式是比较粗放了,粒度比较大,它并没有表明存在什么风险,风险程度如何. 2. ...

  7. springmvc常用注解详解

    1.@Controller 在SpringMVC 中,控制器Controller 负责处理由DispatcherServlet 分发的请求,它把用户请求的数据经过业务处理层处理之后封装成一个Model ...

  8. Spring 各个组件架构

  9. 线程安全Collections.synchronizedList

    ollections.synchronizedList引发的线程安全问题 有些容器是线程安全的(Vector,ConcurrentLinkedQueue等),有些则不是(list等),利用类 似 pr ...

  10. Spring Mvc中Jsp也页面怎么会获取不到Controller中的数据

    ----------Controller ------- package com.test.mvc; import org.springframework.stereotype.Controller; ...