【机器学习】与【数据挖掘】技术下【C++】驱动的【嵌入式】智能系统优化

news2025/1/18 8:42:42

ecde6503e5cb4996a0ff258b3d1ffc28.png

目录

一、嵌入式系统简介

二、C++在嵌入式系统中的优势

三、机器学习在嵌入式系统中的挑战

四、C++实现机器学习模型的基本步骤

五、实例分析:使用C++在嵌入式系统中实现手写数字识别

1. 数据准备

2. 模型训练与压缩

3. 模型部署

六、优化与分析

1. 模型优化

模型量化

模型剪枝

2. 系统优化

内存管理

计算资源分配

电源管理

七、性能评估与优化策略

1. 性能评估指标

2. 性能优化策略

八、实际应用案例 -嵌入式图像分类系统

概述

步骤

1. 数据准备

2. 模型部署

3. 实时推理

九、总结与展望


63748e72dc314943857316f3b1f6a386.gif#pic_center

随着物联网(IoT)和智能设备的普及,嵌入式系统变得越来越重要。而随着人工智能(AI)和机器学习(ML)技术的发展,将这些技术应用于嵌入式系统中可以实现许多智能应用,如智能家居、自动驾驶和工业自动化等。然而,由于嵌入式系统的资源有限,将AI和ML应用到嵌入式系统中面临许多挑战。

一、嵌入式系统简介

a75256bf614b4ba68d12d5f6ad533168.png

嵌入式系统是一种专用计算机系统,通常嵌入到大型系统中,执行特定任务。典型的嵌入式系统包括微控制器(MCU)、单板计算机(SBC)和专用AI加速器。嵌入式系统的主要特点包括:

  • 资源受限:CPU、内存和存储资源较少。
  • 实时性要求:需要在严格的时间限制内完成任务。
  • 专用性强:专为特定任务或设备设计。

二、C++在嵌入式系统中的优势

C++因其高效性和面向对象的特性,在嵌入式系统中得到了广泛应用。其优势包括:

  • 高性能:C++的编译后代码执行效率高,适合资源受限的嵌入式系统。
  • 面向对象:便于代码模块化和重用。
  • 丰富的库支持:标准库和第三方库丰富,便于实现复杂功能。

三、机器学习在嵌入式系统中的挑战

将机器学习模型部署到嵌入式系统中需要克服多种挑战:

  • 模型压缩:减少模型的大小和计算复杂度。
  • 实时性:确保模型推理的实时响应。
  • 资源管理:优化内存和计算资源的使用。

四、C++实现机器学习模型的基本步骤

  1. 数据准备:获取并预处理数据。
  2. 模型训练:在PC或服务器上训练模型。
  3. 模型压缩:使用量化、剪枝等技术压缩模型。
  4. 模型部署:将模型移植到嵌入式系统中。
  5. 实时推理:在嵌入式设备上进行实时推理。

五、实例分析:使用C++在嵌入式系统中实现手写数字识别

以下实例将展示如何在嵌入式系统中使用C++和TensorFlow Lite实现手写数字识别。

c1e2a01d6f8549498683cd2f261d7e47.png

1. 数据准备

我们使用MNIST数据集进行手写数字识别。首先,需要将数据集转换为适合嵌入式系统使用的格式。

#include <fstream>
#include <vector>
#include <iostream>

void read_mnist(const std::string &filename, std::vector<std::vector<uint8_t>> &images) {
    std::ifstream file(filename, std::ios::binary);
    if (file.is_open()) {
        int magic_number = 0;
        int number_of_images = 0;
        int rows = 0;
        int cols = 0;

        file.read((char*)&magic_number, sizeof(magic_number));
        magic_number = __builtin_bswap32(magic_number);
        file.read((char*)&number_of_images, sizeof(number_of_images));
        number_of_images = __builtin_bswap32(number_of_images);
        file.read((char*)&rows, sizeof(rows));
        rows = __builtin_bswap32(rows);
        file.read((char*)&cols, sizeof(cols));
        cols = __builtin_bswap32(cols);

        for (int i = 0; i < number_of_images; ++i) {
            std::vector<uint8_t> image(rows * cols);
            file.read((char*)image.data(), rows * cols);
            images.push_back(image);
        }
    }
}

2. 模型训练与压缩

在PC上使用Python和TensorFlow训练一个简单的卷积神经网络(CNN)模型,并将其转换为适合嵌入式系统的格式。

import tensorflow as tf
from tensorflow.keras.datasets import mnist
from tensorflow.keras.models import Sequential
from tensorflow.keras.layers import Dense, Conv2D, Flatten
import numpy as np

# 加载数据集
(x_train, y_train), (x_test, y_test) = mnist.load_data()
x_train, x_test = x_train / 255.0, x_test / 255.0

# 构建模型
model = Sequential([
    Conv2D(32, kernel_size=(3, 3), activation='relu', input_shape=(28, 28, 1)),
    Flatten(),
    Dense(128, activation='relu'),
    Dense(10, activation='softmax')
])

# 编译和训练模型
model.compile(optimizer='adam', loss='sparse_categorical_crossentropy', metrics=['accuracy'])
model.fit(x_train, y_train, epochs=5)

# 模型量化
converter = tf.lite.TFLiteConverter.from_keras_model(model)
converter.optimizations = [tf.lite.Optimize.DEFAULT]
tflite_model = converter.convert()

# 保存模型
with open('model.tflite', 'wb') as f:
    f.write(tflite_model)

3. 模型部署

使用TensorFlow Lite将模型部署到嵌入式系统中,并进行推理。

#include "tensorflow/lite/c/common.h"
#include "tensorflow/lite/kernels/register.h"
#include "tensorflow/lite/model.h"
#include "tensorflow/lite/interpreter.h"
#include "tensorflow/lite/kernels/register.h"
#include "tensorflow/lite/kernels/register_ref.h"
#include <vector>
#include <iostream>

void run_inference(const std::vector<uint8_t> &input_image) {
    // 加载模型
    const char* model_path = "model.tflite";
    auto model = tflite::FlatBufferModel::BuildFromFile(model_path);
    tflite::ops::builtin::BuiltinOpResolver resolver;
    std::unique_ptr<tflite::Interpreter> interpreter;
    tflite::InterpreterBuilder(*model, resolver)(&interpreter);

    // 分配张量
    interpreter->AllocateTensors();
    int input = interpreter->inputs()[0];
    uint8_t* input_data = interpreter->typed_tensor<uint8_t>(input);

    // 将图像数据复制到输入张量
    std::copy(input_image.begin(), input_image.end(), input_data);

    // 运行推理
    interpreter->Invoke();

    // 获取输出
    int output = interpreter->outputs()[0];
    float* output_data = interpreter->typed_tensor<float>(output);

    // 打印结果
    for (int i = 0; i < 10; ++i) {
        std::cout << "Probability of " << i << ": " << output_data[i] << std::endl;
    }
}

六、优化与分析

在实际应用中,我们需要不断优化模型和系统,以满足嵌入式设备的资源限制和性能需求。以下是一些常见的优化策略和分析方法。

1. 模型优化

模型优化可以通过多种方式进行,包括量化、剪枝和知识蒸馏。

模型量化

模型量化可以显著减少模型的大小和计算量,提高推理速度。

# 模型量化
converter = tf.lite.TFLiteConverter.from_keras_model(model)
converter.optimizations = [tf.lite.Optimize.DEFAULT]
quantized_model = converter.convert()

# 保存量化后的模型
with open('quantized_model.tflite', 'wb') as f:
    f.write(quantized_model)

模型剪枝

模型剪枝可以通过删除不重要的权重来减少模型的大小。

import tensorflow_model_optimization as tfmot

# 定义剪枝参数
pruning_params = {
    'pruning_schedule': tfmot.sparsity.keras.PolynomialDecay(initial_sparsity=0.50,
                                                             final_sparsity=0.90,
                                                             begin_step=0,
                                                             end_step=1000)
}

# 使用剪枝API
model_for_pruning = tfmot.sparsity.keras.prune_low_magnitude(model, **pruning_params)

# 编译模型
model_for_pruning.compile(optimizer='adam',
                          loss='sparse_categorical_crossentropy',
                          metrics=['accuracy'])

# 训练模型
model_for_pruning.fit(x_train, y_train, epochs=2, validation_data=(x_test, y_test))

# 删除剪枝标记并保存模型
model_for_export = tfmot.sparsity.keras.strip_pruning(model_for_pruning)
model_for_export.save('pruned_model.h5')

2. 系统优化

在嵌入式系统中,除了优化模型外,还需要优化系统的各个方面,包括内存管理、计算资源分配和电源管理。

内存管理

在嵌入式系统中,内存资源通常非常有限,因此高效的内存管理是至关重要的。

// 示例代码:高效内存管理
#include <vector>
#include <iostream>

// 使用内存池管理动态内存分配
class MemoryPool {
public:
    MemoryPool(size_t size) : size_(size), memory_(new char[size]), offset_(0) {}

    ~MemoryPool() {
        delete[] memory_;
    }

    void* allocate(size_t size) {
        if (offset_ + size > size_) {
            throw std::bad_alloc();
        }
        void* ptr = memory_ + offset_;
        offset_ += size;
        return ptr;
    }

    void deallocate(void* ptr, size_t size) {
        // 简单实现,不做实际操作
    }

private:
    size_t size_;
    char* memory_;
    size_t offset_;
};

// 示例使用
int main() {
    MemoryPool pool(1024);

    int* a = static_cast<int*>(pool.allocate(sizeof(int) * 10));
    for (int i = 0; i < 10; ++i) {
        a[i] = i;
        std::cout << a[i] << " ";
    }
    std::cout << std::endl;

    pool.deallocate(a, sizeof(int) * 10);

    return 0;
}

计算资源分配

在多核嵌入式系统中,可以使用并行计算来提高模型推理的速度。

// 示例代码:多线程并行计算
#include <thread>
#include <vector>
#include <iostream>

void process_data(int id, const std::vector<int>& data) {
    for (auto val : data) {
        std::cout << "Thread " << id << ": " << val << std::endl;
    }
}

int main() {
    std::vector<int> data = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10};

    std::thread t1(process_data, 1, std::ref(data));
    std::thread t2(process_data, 2, std::ref(data));

    t1.join();
    t2.join();

    return 0;
}

电源管理

在电池供电的嵌入式系统中,电源管理至关重要。可以通过动态电压和频率调节(DVFS)来降低功耗。

// 示例代码:电源管理(伪代码)
#include <iostream>

void adjust_frequency(int level) {
    // 根据需要调整CPU频率
    std::cout << "Adjusting CPU frequency to level: " << level << std::endl;
}

int main() {
    int workload = 50; // 示例工作负载

    if (workload < 20) {
        adjust_frequency(1); // 低频率
    } else if (workload < 70) {
        adjust_frequency(2); // 中等频率
    } else {
        adjust_frequency(3); // 高频率
    }

    return 0;
}

七、性能评估与优化策略

评估和优化模型在嵌入式系统上的性能是确保系统能够满足实际应用需求的重要步骤。

1. 性能评估指标

  • 推理时间:模型从输入到输出的时间。
  • 内存使用:模型运行时的内存占用。
  • 能耗:模型运行时的功耗。

2. 性能优化策略

  • 使用硬件加速:利用硬件平台的AI加速器。
  • 优化编译器:使用针对特定硬件优化的编译器和库,如TensorFlow Lite Micro。
  • 并行处理:在多核系统中使用并行计算提高推理速度。

八、实际应用案例 -嵌入式图像分类系统

4df95d93e16647e78fff05e95b201ece.png

构建一个嵌入式图像分类系统,使用Raspberry Pi和TensorFlow Lite进行实时图像分类。

概述

在本案例中,我们将使用Raspberry Pi和TensorFlow Lite部署一个手写数字识别模型。本文将详细展示如何在嵌入式系统中实现图像分类的每一步,包括数据准备、模型部署和实时推理。

步骤

  1. 数据准备:获取MNIST数据集并转换为适合嵌入式系统使用的格式。
  2. 模型训练与量化:使用预训练的TensorFlow Lite模型。
  3. 模型部署:将模型部署到Raspberry Pi上。
  4. 实时推理:在Raspberry Pi上进行实时图像分类。

1. 数据准备

在C++中读取MNIST数据集,并将其格式化为适合模型输入的形式。

#include <iostream>
#include <fstream>
#include <vector>

void read_mnist(const std::string &filename, std::vector<std::vector<uint8_t>> &images) {
    std::ifstream file(filename, std::ios::binary);
    if (file.is_open()) {
        int magic_number = 0;
        int number_of_images = 0;
        int rows = 0;
        int cols = 0;

        file.read((char*)&magic_number, sizeof(magic_number));
        magic_number = __builtin_bswap32(magic_number);
        file.read((char*)&number_of_images, sizeof(number_of_images));
        number_of_images = __builtin_bswap32(number_of_images);
        file.read((char*)&rows, sizeof(rows));
        rows = __builtin_bswap32(rows);
        file.read((char*)&cols, sizeof(cols));
        cols = __builtin_bswap32(cols);

        for (int i = 0; i < number_of_images; ++i) {
            std::vector<uint8_t> image(rows * cols);
            file.read((char*)image.data(), rows * cols);
            images.push_back(image);
        }
    }
}

int main() {
    std::vector<std::vector<uint8_t>> images;
    read_mnist("train-images-idx3-ubyte", images);

    std::cout << "Read " << images.size() << " images." << std::endl;
    return 0;
}

2. 模型部署

使用TensorFlow Lite的C++ API将量化后的模型部署到Raspberry Pi上。

#include "tensorflow/lite/c/common.h"
#include "tensorflow/lite/kernels/register.h"
#include "tensorflow/lite/model.h"
#include "tensorflow/lite/interpreter.h"
#include <vector>
#include <iostream>
#include <memory>

void run_inference(const std::vector<uint8_t> &input_image) {
    // 加载模型
    const char* model_path = "model.tflite";
    auto model = tflite::FlatBufferModel::BuildFromFile(model_path);
    tflite::ops::builtin::BuiltinOpResolver resolver;
    std::unique_ptr<tflite::Interpreter> interpreter;
    tflite::InterpreterBuilder(*model, resolver)(&interpreter);

    // 分配张量
    interpreter->AllocateTensors();
    int input = interpreter->inputs()[0];
    uint8_t* input_data = interpreter->typed_tensor<uint8_t>(input);

    // 将图像数据复制到输入张量
    std::copy(input_image.begin(), input_image.end(), input_data);

    // 运行推理
    interpreter->Invoke();

    // 获取输出
    int output = interpreter->outputs()[0];
    float* output_data = interpreter->typed_tensor<float>(output);

    // 打印结果
    for (int i = 0; i < 10; ++i) {
        std::cout << "Probability of " << i << ": " << output_data[i] << std::endl;
    }
}

int main() {
    std::vector<uint8_t> image_data(28 * 28); // 假设我们有一个28x28的灰度图像数据
    // 在此处加载图像数据
    run_inference(image_data);
    return 0;
}

 

3. 实时推理

在Raspberry Pi上进行实时推理,需要处理实时获取的图像数据并进行推理。

#include <opencv2/opencv.hpp>
#include <iostream>
#include <vector>
#include "tensorflow/lite/interpreter.h"
#include "tensorflow/lite/kernels/register.h"
#include "tensorflow/lite/model.h"

void preprocess_image(const cv::Mat &image, std::vector<uint8_t> &output_image) {
    cv::Mat resized_image;
    cv::resize(image, resized_image, cv::Size(28, 28));
    cv::cvtColor(resized_image, resized_image, cv::COLOR_BGR2GRAY);

    output_image.assign(resized_image.data, resized_image.data + resized_image.total());
}

void classify_image(const std::vector<uint8_t> &image_data) {
    const char* model_path = "model.tflite";
    auto model = tflite::FlatBufferModel::BuildFromFile(model_path);
    tflite::ops::builtin::BuiltinOpResolver resolver;
    std::unique_ptr<tflite::Interpreter> interpreter;
    tflite::InterpreterBuilder(*model, resolver)(&interpreter);

    interpreter->AllocateTensors();
    int input_index = interpreter->inputs()[0];
    uint8_t* input_data = interpreter->typed_tensor<uint8_t>(input_index);

    std::copy(image_data.begin(), image_data.end(), input_data);
    interpreter->Invoke();

    int output_index = interpreter->outputs()[0];
    float* output_data = interpreter->typed_tensor<float>(output_index);

    for (int i = 0; i < 10; ++i) {
        std::cout << "Class " << i << ": " << output_data[i] << std::endl;
    }
}

int main() {
    cv::VideoCapture cap(0);
    if (!cap.isOpened()) {
        std::cerr << "Error opening video stream" << std::endl;
        return -1;
    }

    while (true) {
        cv::Mat frame;
        cap >> frame;
        if (frame.empty()) {
            break;
        }

        std::vector<uint8_t> image_data;
        preprocess_image(frame, image_data);
        classify_image(image_data);

        cv::imshow("Frame", frame);
        if (cv::waitKey(10) == 27) {
            break;
        }
    }

    cap.release();
    cv::destroyAllWindows();
    return 0;
}

九、总结与展望

在嵌入式系统中使用C++进行机器学习和数据挖掘,包括数据准备、模型训练与压缩、模型部署以及实时推理。未来,随着硬件和算法的不断进步,嵌入式机器学习将会有更加广阔的应用前景,推动物联网、智能制造和智能家居等领域的创新发展。

d6f8de9bc53d443f9b9584c9760c1871.png

 

 

 

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1802110.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

hot100 -- 二分查找

目录 前言 &#x1f382;搜索插入位置 &#x1f33c;搜索二维矩阵 &#x1f33c;排序数组元素第一和最后一个位置 &#x1f33c;旋转排序数组 &#x1f4aa;旋转排序数组中的最小值 &#x1f4aa;两个正序数组的中位数 前言 二分算法学习_时间超限ac:0%-CSDN博客 &#…

Vue10-事件修饰符

一、示例&#xff1a;<a>标签不执行默认的跳转行为 1-1、方式一 <a href"http://www.baidu.com" onclick"event.preventDefault();">点击我</a> 1-2、方式二 1-3、方式三&#xff1a;事件修饰符 二、Vue的六种事件修饰符 2-1、prevent&…

Edge怎么关闭快捷键

Edge怎么关闭快捷键 在Edge浏览器中&#xff0c;你可以通过以下步骤关闭快捷键&#xff1a; 打开Edge浏览器&#xff0c;输入&#xff1a;edge://flags 并按下回车键。 在Flags页面中&#xff0c;搜索“快捷键”(Keyboard shortcuts)选项。 将“快捷键”选项的状态设置为“…

注册小程序

每个小程序都需要在 app.js 中调用 App 方法注册小程序实例&#xff0c;绑定生命周期回调函数、错误监听和页面不存在监听函数等。 详细的参数含义和使用请参考 App 参考文档 。 整个小程序只有一个 App 实例&#xff0c;是全部页面共享的。开发者可以通过 getApp 方法获取到全…

HuggingFace团队亲授大模型量化基础: Quantization Fundamentals with Hugging Face

Quantization Fundamentals with Hugging Face 本文是学习https://www.deeplearning.ai/short-courses/quantization-fundamentals-with-hugging-face/ 这门课的学习笔记。 What you’ll learn in this course Generative AI models, like large language models, often exce…

转让无区域商业管理公司挺批行业包变更

无区域的名称我们可以直接进行名称的申请核准。 从新规施行之后&#xff0c;国家局核名批准难度更高。新申请的无区域名称已经停批了&#xff0c;进行核名将更难&#xff0c;而需要满足一定条件并在成立一年后才能变更升级名称。而这个过程并非易事&#xff0c;难度非常高。可以…

45-1 waf绕过 - 文件上传绕过WAF方法

环境准备: 43-5 waf绕过 - 安全狗简介及安装-CSDN博客然后安装dvwa靶场:构建完善的安全渗透测试环境:推荐工具、资源和下载链接_渗透测试靶机下载-CSDN博客打开dvwa靶场,先将靶场的安全等级调低,然后切换到文件上传 一、符号变异 在PHP中,由于其弱类型特性,有时候仅有一…

JavaSE——抽象类和接口

目录 一 .抽象类 1.抽象类概念 2.抽象类语法 3.抽象类特性 4.抽象类的作用 二. 接口 1.接口的概念 2.语法规则 3.接口的使用 4.接口特性 5.实现多个接口 6.接口间的继承 三.抽象类和接口的区别 一 .抽象类 1.抽象类概念 在面向对象的概念中&#xff0c;所有的对…

SpringCloud整合OpenFeign实现微服务间的通信

1. 前言 1.1 为什么要使用OpenFeign&#xff1f; 虽说RestTemplate 对HTTP封装后, 已经⽐直接使⽤HTTPClient简单⽅便很多, 但是还存在⼀些问题. 需要拼接URL, 灵活性⾼, 但是封装臃肿, URL复杂时, 容易出错. 代码可读性差, ⻛格不统⼀。 1.2 介绍一下微服务之间的通信方式 微…

Zabbix实现邮件和钉钉实时告警(使用python脚本)

告警和通知 告警是监控的主要职能,是指将到达某一阈值事件的消息发送给用户,让用户在事件发生的时候即刻知道监控项处于不正常状态,从而让用户来决定是否采取相关措施。 zabbix中,告警是由一系列的流程组成的,⾸首先是触发器到达阈值,接下是Active对事件信息进行处理,其…

TCP/IP协议分析实验:通过一次下载任务抓包分析

TCP/IP协议分析 一、实验简介 本实验主要讲解TCP/IP协议的应用&#xff0c;通过一次下载任务&#xff0c;抓取TCP/IP数据报文&#xff0c;对TCP连接和断开的过程进行分析&#xff0c;查看TCP“三次握手”和“四次挥手”的数据报文&#xff0c;并对其进行简单的分析。 二、实…

ElasticSearch学习笔记之一:介绍及EFK部署

1. 系统概述 The Elastic Stack&#xff0c;包括Elasticsearch、Kibana、Beats和Logstash&#xff08;也成为ELK Stack&#xff09; Elasticsearch&#xff1a;简称ES&#xff0c;是一个开源的高扩展的分布式全文搜索引擎&#xff0c;是整个Elastic Stack技术栈的核心。它可以…

【MySQL】聊聊MySQL常见的SQL语句阻塞场景

在平时的业务中&#xff0c;可能一个简单的SQL语句也执行很慢&#xff0c;这种情况其实大多数都是要么没有使用索引&#xff0c;要么出现锁竞争造成执行阻塞。本篇主要来介绍具体的场景 CREATE TABLE t ( id int(11) NOT NULL, c int(11) DEFAULT NULL, PRIMARY KEY (id) ) ENG…

用HAL库改写江科大的stm32入门-6-4 PWM驱动舵机

接线图&#xff1a; 如何控制一个舵机 舵机的控制由一个脉冲宽度调制信号(PWM波&#xff09;来实现&#xff0c;该信号在这个实验里使用stm32来发出。 舵机通讯协议&#xff1a; 对应设置参数&#xff1a; ARR的值为19999 CCR的值为500~2500(生成占空比是2.5%~12.5%的波形)…

[经验] 昆山教育网(昆山教育网中小学报名) #媒体#职场发展#微信

昆山教育网&#xff08;昆山教育网中小学报名&#xff09; 昆山教育局网站 网站&#xff1a;昆山市教育局 昆山市教育局全面贯彻执行党和国家的教育方针、政策&#xff0c;落实有关教育工作的法律、法规&#xff1b;负责制定本市教育工作的实施意见和措施&#xff0c;并监督…

Java基础_异常

Java基础_异常 异常体系介绍编译时异常和运行时异常异常的作用异常的处理方式JVM默认的处理方式自己处理&#xff08;捕获异常&#xff09;try...catch灵魂四问Throwable的成员方法 抛出处理 综合练习自定义异常来源Gitee地址 异常体系介绍 异常是什么&#xff1f; 程序中可能出…

LabVIEW2017破解安装教程

LabVIEW2017破解安装教程&#xff1a; 1、新版LabVIEW2017分为32位和64位两个平台&#xff0c;多种语言版本(需要LabVIEW2017中文版的朋友请选择WinChn版本)&#xff0c;大家选择自行选择符合系统的版本下载并解压 2、本次安装以Win 7 64位系统为例&#xff0c;运行“2017LV-64…

【Vscode配置java环境并配置stringboot】

1.VSCODE配置JAVA环境 参考这篇文章配置JAVA环境&#xff1a;连接 java版本&#xff0c;我是win11系统,我下载的JAVA安装版本是下面&#xff0c;是最新版的&#xff1a; 配置环境&#xff1a;步骤很简单&#xff0c;就是向系统环境变量中添加路径&#xff0c;参考上面文章中的…

AddressSanitizer理论及实践:heap-use-after-free、free on not malloc()-ed address

AddressSanity&#xff1a;A Fast Address Sanity Checker 摘要 对于C和C 等编程语言&#xff0c;包括缓冲区溢出和堆内存的释放后重用等内存访问错误仍然是一个严重的问题。存在许多内存错误检测器&#xff0c;但大多数检测器要么运行缓慢&#xff0c;要么检测到的错误类型有…

【Java】解决Java报错:IllegalArgumentException

文章目录 引言1. 错误详解2. 常见的出错场景2.1 非法的参数值2.2 空值或 null 参数2.3 非法的数组索引 3. 解决方案3.1 参数验证3.2 使用自定义异常3.3 使用Java标准库中的 Objects 类 4. 预防措施4.1 编写防御性代码4.2 使用注解和检查工具4.3 单元测试 结语 引言 在Java编程…