前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >专栏 >i.MX283开发板第一个Linux驱动-LED驱动改进

i.MX283开发板第一个Linux驱动-LED驱动改进

作者头像
知否知否应是绿肥红瘦
发布于 2025-02-19 13:20:29
发布于 2025-02-19 13:20:29
11300
代码可运行
举报
文章被收录于专栏:Linux知识Linux知识
运行总次数:0
代码可运行

上一个博客i.MX283开发板第一个Linux驱动讲的是最简单的LED驱动的编写,但是其中还有一些不足。

首先是在利用insmod加载驱动时,需要用指令**mknod /dev/imx283_led c 200 0**手动创建设备节点,否则在/dev下是不会有我们的设备的,应用程序中open("/dev/imx283_led",O_RDWR)必然会失败。

其次是利用register_chrdev函数注册设备会造成设备号的浪费,这个是早期2.4版本内核的注册方法,在Linux2.6及以后的版本都不是很推荐这种方式。

下面就针对上一个LED驱动作下改进。

  • udev、mdev机制

Linux有udev、mdev的机制,而我们的ARM开发板上移植的busybox有mdev机制,然后mdev机制会通过class类来找到相应类的驱动设备来自动创建设备节点 (前提需要有mdev)

udev 是一个用户程序,在 Linux 下通过 udev 来实现设备文件的创建与删除,udev 可以检测系统中硬件设备状态,可以根据系统中硬件设备状态来创建或者删除设备文件。比如使用modprobe 命令成功加载驱动模块以后就自动在/dev 目录下创建对应的设备节点文件,使用rmmod 命令卸载驱动模块以后就删除掉/dev 目录下的设备节点文件。

1.首先要创建一个 cdev结构体变量、class 类和device设备。

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
static struct cdev LED_cdev;//定义一个cdev结构体
static struct class *led_class;//创建一个LED类
static struct device *led_device;//创建一个LED设备 该设备是需要挂在LED类下面的
static int major;//主设备号
static dev_t  dev_id;//设备号 由主设备号和次设备号组合而成

注意:dev_id是为了动态申请设备号创建的变量,申请成功后可以利用MAJOR(dev_id)和MINOR(dev_id)取出主设备号和次设备号。

2.改进**注册与注销字符设备函数**

register_chrdev()的弊端在于它仅仅由一个主设备号就确定了一个设备驱动,因为register_chrdev()的入口参数只有主设备号major和fops结构体,Linux内核最多支持255个字符设备,假设我有255个不同的字符设备需要控制,那么就需要255个主设备号,一下子用光了所有的设备号,这是很不合理的!

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
int __register_chrdev(unsigned int major, //主设备号
                      unsigned int baseminor,
                      unsigned int count,
                      const char *name,//设备名称
                      const struct file_operations *fops)

因此就需要一种合理的方式分配和释放设备号,Linux 2.6及以后的内核就提供了这种方式,下面这个函数就是用来申请设备号:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
int alloc_chrdev_region(dev_t *dev, unsigned baseminor, unsigned count, const char *name) 
/*
dev:需要申请的设备号  
baseminor:次设备号起始位置
count:需要申请次设备号的个数 
name:设备名称
*/

这样就保证了每个设备只对应一个主设备号和一个次设备号 。同样的,有申请设备号必然有注销设备号,注销设备号函数如下:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
void unregister_chrdev_region(dev_t from, unsigned count)
/*
from:需要注销设备号的起始位置
count:个数
*/

申请完设备号,就需要向内核注册字符设备,这里需要首先需要使用cdev_init()初始化一个cdev结构体。

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
struct cdev {
	struct kobject kobj;
	struct module *owner;//一般为THIS_MODULE
	const struct file_operations *ops;
	struct list_head list;
	dev_t dev;//设备号
	unsigned int count;//设备号数量
};

void cdev_init(struct cdev *cdev, const struct file_operations *fops)
/*
cdev:初始化一个cdev结构体
fops:将设备驱动file_operations结构体赋给cdev的ops变量 
*/

接下来需要向刚刚初始化好的cdev结构体中添加字符设备:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
int cdev_add(struct cdev *p, dev_t dev, unsigned count)
/*
p:初始化好的cdev结构体
dev:设备号
count:设备数量
*/
  • 改进后注册设备函数:
代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
static int __init led_init(void)
{ 
   /*1.申请或者指定主设备号 此处由内核动态分配1个设备号*/
   alloc_chrdev_region(&dev_id, 0, 1, DEVICE_NAME);
   /*2.初始化 LED_DEV结构体*/
   cdev_init(&LED_cdev, &led_fops);
   /*3.向LED_cdev添加1个设备*/
   cdev_add(&LED_cdev,dev_id, 1);
   /*4.创建一个LED类*/
   led_class = class_create(THIS_MODULE,"led_class");
   /*5.在LED类下面创建一个LED设备 然后mdev通过这个自动创建/dev/"DEVICE_NAME"*/
   led_device = device_create(led_class,NULL,dev_id,NULL,DEVICE_NAME);
   printk("module init ok\n");
   return 0; 
}

class_create是类创建函数,需要引用头文件#include <linux/device.h>

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
#define class_create(owner, name)		\
({						\
	static struct lock_class_key __key;	\
	__class_create(owner, name, &__key);	\
})

/*
owner:THIS_MODULE
name:类名字,可以随意
*/

device_create用于在指定类下面创建一个设备

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
struct device *device_create(struct class *class, struct device *parent,
			     dev_t devt, void *drvdata, const char *fmt, ...)
{
	va_list vargs;
	struct device *dev;

	va_start(vargs, fmt);
	dev = device_create_vargs(class, parent, devt, drvdata, fmt, vargs);
	va_end(vargs);
	return dev;
}
/*
class:指定类,这里指定上一步创建的类
parent:父设备,一般为NULL
devt:设备号,可以通过MKDEV构建出来
drvdata:是设备可能会使用的一些数据,一般为 NULL
fmt:设备名字,如果设置 fmt=xxx 的话,就会生成/dev/xxx这个设备文件。返回值就是创建好的设备。
MKDEV是个宏定义,作用是根据已有的主设备号和次设备号构建一个dev_t类型的设备号。
*/
  • 改进后注销设备函数:
代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
static void __exit led_exit(void)
{
  /*1.删除LED_cdev结构体*/
  cdev_del(&LED_cdev); 
  /*2.注销设备 cat /proc/devices下不可见*/
   unregister_chrdev_region(dev_id,1);
  /*3.删除LED设备*/
  device_destroy(led_class, dev_id);
  /*4.删除LED类*/
  class_destroy(led_class);
  printk("module exit ok\n");
}

device_destroy函数是从指定类下面删除一个设备

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
void device_destroy(struct class *class, dev_t devt)
{
	struct device *dev;

	dev = class_find_device(class, NULL, &devt, __match_devt);
	if (dev) {
		put_device(dev);
		device_unregister(dev);
	}
}
//class:指定类            devt:设备号
代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
void class_destroy(struct class *cls)
{
	if ((cls == NULL) || (IS_ERR(cls)))
		return;

	class_unregister(cls);
}
//cls: 需要删除的class

下面给出完整的驱动函数:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
/*
   GPIO Driver driver for EasyARM-iMX283
*/
#include <linux/module.h>//模块加载卸载函数
#include <linux/kernel.h>//内核头文件
#include <linux/types.h>//数据类型定义
#include <linux/sched.h>
#include <linux/init.h>
#include <linux/fs.h>//file_operations结构体
#include <linux/device.h>//class_create等函数
#include <linux/ioctl.h>
#include <linux/delay.h>
#include <linux/bcd.h>
#include <linux/capability.h>
#include <linux/rtc.h>
#include <linux/cdev.h>
#include <linux/gpio.h>//gpio_request  gpio_free函数 

#include <../arch/arm/mach-mx28/mx28_pins.h>

#define DEVICE_NAME	"imx283_led"//驱动名称
#define LED_GPIO	MXS_PIN_TO_GPIO(PINID_LCD_D23)		//for 283 287A/B

static int led_open(struct inode *inode ,struct file *flip)
{

   int ret = -1;
   gpio_free(LED_GPIO); 
   ret = gpio_request(LED_GPIO, "LED1");
   printk("gpio_request = %d\r\n",ret);
   return 0;
}


static int led_release(struct inode *inode ,struct file *flip)
{
  gpio_free(LED_GPIO);
  return 0;  
}


static int led_write(struct file *filp, const char __user *buf, size_t count,
                loff_t *f_pos)
{
   int ret = -1;
   unsigned char databuf[1];
   ret = copy_from_user(databuf,buf,1);
   if(ret < 0 ) 
   	{
   	  printk("kernel write error \n");
	  return ret;
   	}
   gpio_direction_output(LED_GPIO, databuf[0]);
   return ret; 
}


static  ssize_t led_read(struct file *filp, const char __user *buf, size_t count,
                loff_t *f_pos)
{
    return 0;
}

static struct file_operations led_fops={
	.owner		= THIS_MODULE,
	.open 		= led_open,
	.write		= led_write,
	.read       = led_read,
	.release	= led_release,
};


static struct cdev LED_cdev;//定义一个cdev结构体
static struct class *led_class;//创建一个LED类
static struct device *led_device;//创建一个LED设备 该设备是需要挂在LED类下面的
static int major;//主设备号
static dev_t  dev_id; 

static int __init led_init(void)
{ 
    /*1.申请或者指定主设备号 此处由内核动态分配设备号*/
    alloc_chrdev_region(&dev_id, 0, 1, DEVICE_NAME);
	/*2.初始化 LED_DEV结构体*/
   	cdev_init(&LED_cdev, &led_fops);
	/*3.向LED_cdev添加设备*/
   	cdev_add(&LED_cdev,dev_id, 1);
	
   //major = register_chrdev(0,DEVICE_NAME,&led_fops);  
   //if(major < 0)
   //{
   // printk("register_chrdev error %d\n",major); 
   // return major;
   //}
   //4.创建一个LED类
   led_class = class_create(THIS_MODULE,"led_class");
   //5.在LED类下面创建一个LED设备 然后mdev通过这个自动创建/dev/"DEVICE_NAME"
   led_device = device_create(led_class,NULL,dev_id,NULL,DEVICE_NAME);
   printk("module init ok\n");
   return 0; 
}


static void __exit led_exit(void)
{
  /*1.删除LED_cdev结构体*/
  cdev_del(&LED_cdev); 
  /*2.注销设备 cat /proc/devices下不可见*/
  //unregister_chrdev(major, DEVICE_NAME);
   unregister_chrdev_region(dev_id,1);
  /*3.删除LED设备*/
  device_destroy(led_class, dev_id);
  /*4.删除LED类*/
  class_destroy(led_class);
  printk("module exit ok\n");
}

module_init(led_init);
module_exit(led_exit);
MODULE_LICENSE("GPL");
MODULE_AUTHOR("xzx2020");

3.测试

将上述驱动文件,编译生成.ko文件在开发板上测试。

首先看下/dev下有么有LED设备节点

此时没有任何LED设备节点,然后再加载驱动。

驱动加载成功,我们再到/dev下看看

已经自动生成了设备设备节点,主设备号250,次设备号0.

最后,我们再卸载掉这个驱动,并再次查看/dev和/proc/devices

都没有“imx283_led”这个设备存在,说明已经被删除掉了。

4.总结

1.实际上新的设备注册方法就是将以前的拆分罢了。

register_chrdev()原型如下:

2.如果有多个同一类型的设备怎么注册?比如说有4个LED需要控制?

有两种方法,第一种当然是有几个设备就注册几个设备号,这样肯定没问题,但是如果设备数量很多,这种方法就不可取了。

第二种就是利用次设备号,这些设备共享一个主设备号,用次设备号区分彼此。

驱动程序中注册和注销函数就要作如下修改,这里以4个LED为例:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
static int major;//主设备号
static struct device *led_device[4];//4个设备
代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
static int __init led_init(void)
{ 
    unsigned char i; 
    /*1.申请或者指定主设备号 此处由内核动态分配设备号*/
    alloc_chrdev_region(&dev_id, 0, 4, DEVICE_NAME);//需要分配4个次设备号,0,1,2,3
	major = MAJOR(dev_id);//取出主设备号
	/*2.初始化 LED_DEV结构体*/
   	cdev_init(&LED_cdev, &led_fops);
	/*3.向LED_cdev添加设备*/
   	cdev_add(&LED_cdev,dev_id, 4);//添加4个设备
    //4.创建一个LED类
    led_class = class_create(THIS_MODULE,"led_class");
    //5.在LED类下面创建一个LED设备 然后mdev通过这个自动创建/dev/"DEVICE_NAME"
    for(i=0;i<4;i++)//创建4个设备
   	{
      led_device[i] = device_create(led_class,NULL,MKDEV(major, i),NULL,"imx283_led%d",i);
   	}
   printk("module init ok\n");
   return 0; 
}
代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
static void __exit led_exit(void)
{
  unsigned char i; 
  /*1.删除LED_cdev结构体*/
  cdev_del(&LED_cdev); 
  /*2.注销设备 cat /proc/devices下不可见*/
   unregister_chrdev_region(dev_id,4);
  /*3.删除LED设备*/
  for(i=0;i<4;i++)
  {
       device_destroy(led_class, MKDEV(major, i));
  }
  /*4.删除LED类*/
  class_destroy(led_class);
  printk("module exit ok\n");
}

编译生成.ko文件,用insmod加载,查看cat /proc/devices

只生成了1个LED设备,原因是这4个LED共享一个主设备号,同时也共享一个file_operations结构体,它们只是名字和次设备号不同,再查看下/dev目录:

那么它们既然共享同一个file_operations结构体,那该如何单独控制每一个LED呢?

file_operations结构体的write函数、read函数和open函数的入口参数都可以取出LED的设备号

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
//write函数
static int led_write(struct file *filp, 
                     const char __user *buf, 
                     size_t count,
                     loff_t *f_pos)
//read函数
static  ssize_t led_read(struct file *filp, 
                         const char __user *buf, 
                         size_t count,
                         loff_t *f_pos)
int minor =MINOR(filp->f_path.dentry->d_inode->i_rdev);//取出次设备号
代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
static int led_open(struct inode *inode ,struct file *flip)//open 函数
int minor = MINOR(inode->i_rdev);//取出次设备号
//int minor = iminor(inode);//取出次设备号

这样在应用程序中,调用open(/dev/led1)时,上面取出的minor=1,open(/dev/led3),上面的minor=3.write调用也是类似的情况,这样驱动程序只要根据不同的次设备号对相应的LED进行操作,就可以实现同一套驱动控制多个同类设备,且没有占用多个主设备号。

本文参考:

1.《嵌入式Linux应用完全开发手册》

2.《【正点原子】I.MX6U嵌入式Linux驱动开发指南V1.0》

3.分析Linux驱动函数register_chrdev_region

本文参与 腾讯云自媒体同步曝光计划,分享自作者个人站点/博客。
原始发表:2025-02-19,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
暂无评论
推荐阅读
面试官:说说JVM内存整体结构?
Java 虚拟机定义了若干种程序运行期间会使用到的运行时数据区,其中有一些会随着虚拟机启动而创建,随着虚拟机退出而销毁。另外一些则是与线程一一对应的,这些与线程一一对应的数据区域会随着线程开始和结束而创建和销毁。
鲁大猿
2024/01/04
2440
面试官:说说JVM内存整体结构?
java:线上问题排查常用手段
然后执行 jmap -histo:live 7320 (注:如果输出内容太多,只想看排名前10的,可以加 | head -10)
菩提树下的杨过
2018/09/20
8340
java:线上问题排查常用手段
【Java】Java - GC 是如何工作的
Java — How GC works. One of the most notable features of… | by RR | Jul, 2023 | Medium
阿东
2024/05/08
1760
【Java】Java - GC 是如何工作的
JVM堆外内存问题排查
JVM 堆内存一般分析的比较多,本篇谈谈堆外内存问题排查,通常我们需要排查堆外内存的原因是系统整个内存使用飙高,但是堆内内存使用正常。这时候就需要分析堆外内存了
方丈的寺院
2019/08/05
5.8K0
「周一电台 x 训练营」从三道题开始,认识Java内存
几乎所有的对象实例以及数组在堆里分配内存。Java堆还是垃圾收集器(Garbage Collection,GC)管理的主要区域,因此我们也可以叫它GC堆,请勿叫做垃圾堆!
翊君
2022/03/15
3040
「周一电台 x 训练营」从三道题开始,认识Java内存
JVM 面试深入理解内存模型和垃圾回收(二)
https://docs.oracle.com/javase/specs/jvms/se8/html/jvms-2.html#jvms-2.5 >>>
架构探险之道
2023/03/04
4660
JVM 面试深入理解内存模型和垃圾回收(二)
深入浅出java虚拟机系列:(一)jvm 内存区域
java与c++之间有一堵由动态内存分配和垃圾收集技术所谓成的“高墙”,墙外面的人想进去,墙里面的人却想出来。
爱笑的架构师
2020/09/24
2570
深入浅出java虚拟机系列:(一)jvm 内存区域
JVM知识学习与巩固
JVM是Java Virtual Machine(Java虚拟机)的缩写,JVM是一种用于计算设备的规范,它是一个虚构出来的计算机,是通过在实际的计算机上仿真模拟各种计算机功能来实现的。
用户3003813
2018/09/06
5100
JVM知识学习与巩固
jvm系列(四):jvm调优-命令篇
运用jvm自带的命令可以方便的在生产监控和打印堆栈的日志信息帮忙我们来定位问题!虽然jvm调优成熟的工具已经有很多:jconsole、大名鼎鼎的VisualVM,IBM的Memory Analyzer等等,但是在生产环境出现问题的时候,一方面工具的使用会有所限制,另一方面喜欢装X的我们,总喜欢在出现问题的时候在终端输入一些命令来解决。所有的工具几乎都是依赖于jdk的接口和底层的这些命令,研究这些命令的使用也让我们更能了解jvm构成和特性。 Sun JDK监控和故障处理命令有jps jstat jmap jh
纯洁的微笑
2018/04/19
1.9K0
jvm系列(四):jvm调优-命令篇
Java 内存模型之堆内存(Heap)
1、什么是 Perm Gen? Perm Gen : Permanent Generation  Perm Gen 区是一个特殊的JVM内存区,因为它用来存储用来描述 Class 的  元数据(Class 可以不属于Java语言的一部分,也可以属于),诸如:描述类及其方法。  在大的应用中该区一会儿就满了,并抛出错误:java.lang.OutOfMemoryError: PermGen  然而无论你怎么设置 -Xmx 也不管用。  因为设置其大小的参数不是 -Xmx,而是 -XX:PermGen, -XX:MaxPermGen (不同Java版本略有变化)  2、Heap VS. Stack VS. Perm Heap(堆内存):  使用Java语言创建的所有的引用对象类型,都在此存储。并由 GC (Garbage Collection)对其进行管理,  诸如:释放不再被程序引用的对象所占据的内存。  Stack(栈内存):  与 Heap 相对的是,Stack 存放基础数据类型。诸如:int, char 等。  由程序的执行顺序控制变量的进出栈顺序,而不是由 GC 控制栈内存的管理。  Perm(持久内存):  用于存储类的元数据。诸如:类的定义,方法的定义等。  Perm 的生命周期与 JVM 绑定,而 Heap 的生命周期与程序绑定。  二、堆内存(Heap) 与 Garbage Collection 理解 GC (Garbage Collection),需要理解 Heap 。  JVM 的 Heap 堆内存在物理上被划分为两部分:Young Gen, Old Gen  1、 JVM 内存管理之:Young Gen 所有新创建的 Object 首先被放在 Young Generation 内存区。  如果 Young Generation 内存区满了,则执行 Garbage Collection 。这种 GC 称为 Minor GC。  Young Generation 区又分为三部分: Eden Memory,Survivor0 Memory (S0),Survivor1 Memory(S1).  Young Generation 内存区要点:  1、绝大多数新建的 Object 被放在 Eden Memory  2、如果 Eden Memory 内存满了,则进行 GC 操作。     同时把未被 GC 的 Object 移动到 S0 或 S1 中。     此时 Minor GC 也会检查和移动 S0 和 S1 中的对象。     最后使 S0,S1 其中一个置为空。  3、多次 GC 后仍然未被 GC 的 Object 将被移动到 Old Gen 内存区中。     通常 Object 会被 GC 设定一个轮询的阀值。  2、 JVM 内存管理之:Old Gen Old Gen 内存区存放了经过多次 Minor GC 后仍然不能被 GC 的 Object。  与 Young Gen 相同,当 Old Gen 区满了之后将执行 GC 操作,该操作称为:Major GC。  耗用的时间也相对较长。  stop-the-world 事件  Young Gen 和 Old Gen 都可以主动触发 stop-the-world 事件,挂起所有任务,执行 GC 操作。  被挂起的任务只有在 GC 执行完毕后,才会恢复执行。  多数情况下, GC 性能调优(GC tuning)就是指降低 stop-the-world 时 GC 执行的时间。  三、Perm Gen  JVM 在 Permanent Generation 或 Perm Gen 内存区中存放应用程序的元数据  (application metadata),用来描述类及其方法的原始信息。  注意:Perm Gen 不是 Heap 的一部分。  Perm Gen 被 JVM 使用于应用程序运行期间(runtime),基于应用所使用到的类。  Perm Gen 中同时包括 Java SE 包中的类。  Perm Gen 只有在执行 Full GC 时才会被 GC。  四、内存管理调优参数 -Xms  设置JVM启动时的堆内存(Heap)的大小  -Xmx For setting the maximum heap size.  设置堆内存(Heap)的最大值  -Xmn  设置 Young Gen 内存区的大小  -XX:PermGen  设置 Perm Gen 内存的初始大小  -XX:MaxPermGen  设置 Perm Gen 内存的最大值  -XX:SurvivorRatio  设置 Eden Gen 与 S0 Gen,S1 Gen 内存的大小比。默认值:8  例如:  Yo
凯哥Java
2022/12/15
5500
Java 内存模型之堆内存(Heap)
java9系列(九)Make G1 the Default Garbage Collector
本文主要研究下JEP 248: Make G1 the Default Garbage Collector
code4it
2018/09/17
8330
java 资深程序员第一课;jvm优化、了解jvm运行加载class变量过程
        1、首先运行程序,Demo1_car.java就会变为Demo1_car.class,将Demo1_car.class加入方法区,检查是否字节码文件常量池中是否有常量值,如果有,那么就加入运行时常量池
冯杰宁
2019/07/01
6010
java 资深程序员第一课;jvm优化、了解jvm运行加载class变量过程
频繁GC (Allocation Failure)及young gc时间过长分析
本文主要分析一个频繁GC (Allocation Failure)及young gc时间过长的case。
code4it
2018/09/17
13.2K0
java内存分配和String类型的深度解析
在java语言的所有数据类型中,String类型是比较特殊的一种类型,同时也是面试的时候经常被问到的一个知识点,本文结合java内存分配深度分析关于String的许多令人迷惑的问题。下面是本文将要涉及到的一些问题,如果读者对这些问题都了如指掌,则可忽略此文。
哲洛不闹
2018/09/19
7680
java内存分配和String类型的深度解析
JVM内存管理
Java内存管理是一项持续的挑战,同时也是锻造出可拓展应用的必备技能。本质上,Java内存管理就是一个为新对象分配内存和释放无用对象内存的过程。
码代码的陈同学
2018/06/03
2.3K0
JVM内存管理
原 荐 JVM笔记整理
不对之处还望指正。 垃圾回收 1. 如何判断对象是垃圾对象? 引用计数法 在对象中添加一个引用计数器,当有地方引用这个对象的时候,引用计数器的值+1,当引用失效时,则值-1. 此方式不能解决循环引用
石奈子
2018/06/13
5790
java(9)-深入浅出GC垃圾回收机制
1、本文了解GC垃圾回收机制,深入理解GC后才明白,为啥FGC会导致stop-the-world。 2、了解GC算法。
黄规速
2022/04/14
1K0
java(9)-深入浅出GC垃圾回收机制
干货 | 一文看懂JVM内存布局及GC原理
杨俊明,携程云客服平台研发部软件技术专家。从事IT行业10余年,腾讯云+社区、阿里云栖社区、华为云社区认证专家。近年来主要研究分布式架构、微服务、java技术等方向。
携程技术
2019/08/29
1.2K0
干货 | 一文看懂JVM内存布局及GC原理
jvm系列--GC
一般情况下,当新对象生成,并且在Eden申请空间失败时,就会触发Scavenge GC,对Eden区域进行GC,清除非存活对象,并且把尚且存活的对象移动到Survivor区。
Dlimeng
2023/06/29
1930
jvm系列--GC
JVM架构和GC垃圾回收机制(JVM面试不用愁)[通俗易懂]
JVM全称是Java Virtual Machine(Java虚拟机),Java虚拟机是一种程序虚拟机(相对操作系统虚拟机),Java的运行环境实现跨平台。
全栈程序员站长
2022/08/11
4260
JVM架构和GC垃圾回收机制(JVM面试不用愁)[通俗易懂]
相关推荐
面试官:说说JVM内存整体结构?
更多 >
LV.4
adong499
目录
  • 1.首先要创建一个 cdev结构体变量、class 类和device设备。
  • 2.改进**注册与注销字符设备函数**
  • 3.测试
  • 4.总结
  • register_chrdev()原型如下:
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档